V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
James369
V2EX  ›  C++

C++标准库 std 里面简直就是另外一个世界

  •  
  •   James369 · 2021-01-20 09:51:40 +08:00 · 11808 次点击
    这是一个创建于 1432 天前的主题,其中的信息可能已经有所发展或是发生改变。
    在写 C++的时候,不小心点进 std 标准库的.h 头文件,只是看了一眼它的源代码。
    我去,一堆的 template 操作,一堆的__下划线,一堆的...变参。。。
    仿佛进入了另外一个世界,C++的水真深啊。
    我想如果看懂 std 源码,我觉得差不多也就学成了吧。
    第 1 条附言  ·  2021-01-20 11:23:25 +08:00
    我认为并不是炫技,std 库从侧面表明,编写 sdk 或封装库给别人使用时,也应该采用 template 这种模式?。
    第 2 条附言  ·  2021-01-21 09:17:19 +08:00
    有些 v 友提到 C/C++混用会产生较多问题,那么是否可以用 g++指定编译 C++来避免
    83 条回复    2021-08-09 20:53:54 +08:00
    towry
        1
    towry  
       2021-01-20 09:58:11 +08:00   ❤️ 2
    看懂文言文不代表能写出好的文章
    auto8888
        2
    auto8888  
       2021-01-20 10:06:04 +08:00
    能完全看懂 std 源码应该可以说得上精通 C++了吧。。。。

    ![image.png]( https://i.loli.net/2021/01/20/2NlBvkcO3qHarzT.png)

    看的想死
    yanqiyu
        3
    yanqiyu  
       2021-01-20 10:06:25 +08:00 via Android
    下划线只是为了避免不必要的冲突,至于一堆 template...嗯,因为人家叫做 STL
    James369
        4
    James369  
    OP
       2021-01-20 10:08:42 +08:00
    @towry 我翻译一下:精通砖头泥水铲子,但不一定会盖房子。
    Twice
        5
    Twice  
       2021-01-20 10:10:22 +08:00   ❤️ 1
    候捷老师的 《 STL 源码剖析》 ,都是大师啊
    Twice
        6
    Twice  
       2021-01-20 10:11:50 +08:00
    而且之前看他视频,也说其实 stl 里面一些容器类,是有优化空间的🤣,但是还远没这水平
    James369
        7
    James369  
    OP
       2021-01-20 10:13:10 +08:00
    @Twice 可以说,template 完全是另外一种编程模式,神奇
    shunia
        8
    shunia  
       2021-01-20 10:44:55 +08:00   ❤️ 1
    我就想说 2 楼,搞 C 语言就必须用这种我一眼看过去直接眼花的字体和配色吗?
    你们这些底层开发人员就不能对自己好一点,搞一些现代化的东西,非得整电话机 010101 那套吗?
    而且现在市面上方便好用的 C 的 IDE 多的是吧?

    我是真的替你们感到眼睛累。。。手动狗头
    CismonX
        9
    CismonX  
       2021-01-20 10:47:21 +08:00 via iPhone   ❤️ 2
    你可以把 C++ 的类型系统当作另外一门(纯函数式的)语言。如果熟悉函数式编程的思想,template metaprogramming (不限 C++)并不是非常困难

    另外提醒一下,双下划线和单下划线加大写字母开头的名称都是预留字,只有语言实现里面允许用(比如在 STL 或者 libc 中)
    blodside
        10
    blodside  
       2021-01-20 10:50:07 +08:00
    <type_traits> 里面的那堆东西更有意思,模板真好玩
    myid
        11
    myid  
       2021-01-20 10:53:50 +08:00   ❤️ 8
    炫技往往是坑,容易走火入魔。

    不在其位,别谋其政。如果不是开发基础库,那么用不着那些个。C++ 和 C 的妙处根部不在于用了多少它的特性,而在于如何用尽可能它的最简单的特性最高效的完成既定任务。

    话一句话说,能用 struct 搞定的,别硬用 class 。能用普通函数搞定的,没必要非得 template 化。能用 C 风格的字符数组搞定,就没必要用 std::string 类。

    简单是力量的保证。直白易懂是可持久可维护的护身符。
    defphilip
        12
    defphilip  
       2021-01-20 10:59:43 +08:00
    里面的 template 完全就不难啊。。。就一堆类型推导
    hitmanx
        13
    hitmanx  
       2021-01-20 10:59:44 +08:00
    不同的编程范式带来的陌生感。
    XIVN1987
        14
    XIVN1987  
       2021-01-20 11:09:04 +08:00   ❤️ 3
    @myid
    你这说法和书上说的不一样啊

    书上都说能用 std::string,不用 C 风格的字符数组;能用 std::array,不用 C 风格的数组
    focux
        15
    focux  
       2021-01-20 11:29:25 +08:00
    那你还不如看 boost 源码呢
    skyworker
        16
    skyworker  
       2021-01-20 11:32:42 +08:00
    泛型是当时 C++的一个风格, 忘记了好像是相对于"对象 /继承"这种 "运行时多态" 之外, 通过 template 技术来实现 "编译时多态", 不过貌似当时被排斥为"异端"
    auto8888
        17
    auto8888  
       2021-01-20 11:43:29 +08:00
    @shunia IDE 是 qt creator 主题 dark 字体 courier 请指教 /doge
    abc612008
        18
    abc612008  
       2021-01-20 11:47:13 +08:00   ❤️ 9
    @myid 建议直接用 c
    1490213
        19
    1490213  
       2021-01-20 11:48:55 +08:00 via Android
    组里部分老 C++ 代码不好的两个倾向:
    一,追求技巧和花样,县城盖白宫。
    二,半吊子整出的幺蛾子多,配合起来困难。
    shunia
        20
    shunia  
       2021-01-20 11:55:02 +08:00
    @auto8888 #17 我不是 C 程序员,完全不懂哈,我只是觉得您的截图,字体和配色太花眼了,我第一眼看过去就觉得看代码的成本太高。虽然 IDE 只是点缀,但是从某一个角度来说,配合熟练并且本身就更优秀的 IDE,应该相对来说更能提高工作效率。当然这点我有点主观,看看就好。

    另外如果只考虑 IDE 本身,并且非要推荐的话:
    假如没有特殊情况的话,比如 sublime text,相对来讲默认样式要养眼很多。
    再现代化的就可以考虑 vscode 或者 Jetbrain 家的产品是否能满足你的开发要求。

    我不懂 C/C++,所以考虑不到这些 IDE 是否适合对应的工作流。
    shunia
        21
    shunia  
       2021-01-20 11:57:31 +08:00
    ![比如我用 sublime 打开 libwebp 的情况,相对来说要清晰很多吧?]( https://tva1.sinaimg.cn/large/008eGmZEly1gmu0v44k6rj31d90u0b0c.jpg)
    mingl0280
        22
    mingl0280  
       2021-01-20 12:00:46 +08:00   ❤️ 1
    @myid
    我想避免满天飞的 void*,所以才用 template 的……
    因为以前的代码是 C 升级上来的,真的是满天飞的 unnamed type 和 void*以及各种强制类型转换,这种时候你就知道 C++的带类型和语义化的好处了。
    另外,C 风格字符数组这个东西我现在跟我同事说了,不是万不得已不要用,因为有些东西根本不应该被转换为字符数组,而有些东西你用字符数组带来的裸指针的麻烦比用容器更大。
    aihimmel
        23
    aihimmel  
       2021-01-20 12:03:24 +08:00 via Android
    Jirajine
        24
    Jirajine  
       2021-01-20 12:04:22 +08:00 via Android   ❤️ 2
    当你对 c++感到蛋疼的时候,去看看 rust,你会发现一个新世界。
    Leviathann
        25
    Leviathann  
       2021-01-20 12:28:11 +08:00 via iPhone
    @Jirajine 是更蛋疼还是相反。。
    e583409
        26
    e583409  
       2021-01-20 13:08:57 +08:00
    @Jirajine 洗耳恭听
    XIVN1987
        27
    XIVN1987  
       2021-01-20 13:16:13 +08:00
    @Jirajine
    语法和 C 、C++、C#、JAVA 这些 C-like 都不一样,,至少从语法上肯定是个新世界
    AlohaV2
        28
    AlohaV2  
       2021-01-20 13:18:24 +08:00
    template 比 macro 绝大多情况下友好多了,相信我。
    STL 的作用就是让使用者不必关心这些实现细节,除非使用者要讲究细节。
    自己的库封装给用户的时候,不一定 template 就为王,要根据场景而定的。最好的结局是尽管你可能用到了 template,但是用户使用的时候几乎无感。
    nightwitch
        29
    nightwitch  
       2021-01-20 13:31:18 +08:00
    @myid
    在 C++里面 class 和 struct 除了默认的访问和继承权限不一样以及 template class 以外,其他是一个东西
    nnqijiu
        30
    nnqijiu  
       2021-01-20 13:34:30 +08:00
    c 风格和 c++风格混用才是 c++让人蛋疼的地方
    nightwitch
        31
    nightwitch  
       2021-01-20 13:37:36 +08:00
    https://github.com/electronicarts/EASTL
    推荐 EASTL,名字没有混淆过(因为命名空间在 eastl::),虽然不是完整的标准库,但是可读性很好,读起来和普通 c++代码差不多。

    其实标准库没有想象的难,因为标准库的实现的东西都有 cppreference 可以参考,各个模块之间耦合也不深,而且可以多个标准库(libc++,libstdc++,msvcSTL)和仿标准库(eastl, folly)交叉验证着读,除了 iostream 之类的糟粕以外,容器和算法读起来都应该不会有太多困难。
    wdhwg001
        32
    wdhwg001  
       2021-01-20 15:05:29 +08:00 via iPhone
    标准库都难读的话 ranges 岂不是更魔法文字…
    AndyAO
        33
    AndyAO  
       2021-01-20 15:16:55 +08:00
    template 是元编程技术,对于很基础的类库,使用元编程技术能够极大地提升开发效率,但是由于直接对语言本身进行了改动,所以相比起其他的代码,你需要更多的学习才能看懂.

    其他语言的类库也会大量的利用元编程技术,例如 Java 的 Spring(反射)和 Ruby on Rails.

    当然,如果单纯看元编程的灵活性,在这方面最厉害的是 LISP 以及方言.

    以上观点参考自松本行弘的<代码的未来>
    neocanable
        34
    neocanable  
       2021-01-20 15:20:50 +08:00
    哎,我觉得我从来就没有学会过 c++
    yazinnnn
        35
    yazinnnn  
       2021-01-20 15:26:00 +08:00
    rust 不是 c-like ?
    myid
        36
    myid  
       2021-01-20 15:28:42 +08:00
    @abc612008 C++有它的好处。我们不妨取二者最好的部分来用。
    myid
        37
    myid  
       2021-01-20 15:30:33 +08:00
    @nnqijiu 好奇中。举一个小例子?
    @neocanable 你不是一个人在战斗。。。
    myid
        38
    myid  
       2021-01-20 15:41:45 +08:00
    @XIVN1987 绝大多数 C++书这么讲。我信了,直到动手编写代码到了一定量,遇到坑,才醒悟。别盲目相信书。卖瓜的都说瓜甜,卖风油精的讲治百病。C++标准库里的 std::string, std::set 等不见得符合“简单、直接、齐活”的要求。以前对 c-style char array 很不待见,如今领会到了它存在的理由和价值。好比武器,不一定越高级,功能越齐全,就越好越适合。
    l00t
        39
    l00t  
       2021-01-20 16:21:33 +08:00   ❤️ 1
    @myid #36 C++ 和 C 揉在一起就是它最坑的部分。
    myid
        40
    myid  
       2021-01-20 16:24:23 +08:00
    @towry 妙语!赞。
    myid
        41
    myid  
       2021-01-20 16:25:52 +08:00   ❤️ 1
    @l00t 把 C++和 C 最混沌最难用最易出错最危险的揉在一起,是最坑的。
    salamanderMH
        42
    salamanderMH  
       2021-01-20 16:38:21 +08:00
    侯捷的《 STL 源码剖析》,看了才知道水很深。
    786375312123
        43
    786375312123  
       2021-01-20 17:17:55 +08:00
    @myid “能用 C 风格的字符数组搞定,就没必要用 std::string 类。”

    啊?
    stirlingx
        44
    stirlingx  
       2021-01-20 19:23:29 +08:00   ❤️ 2
    学一下 erlang,你会发现变量不能赋值
    Narcissu5
        45
    Narcissu5  
       2021-01-20 19:31:08 +08:00
    让我想起了一段 play2 里面的 scala 代码:

    class ApplicativeOps[M[_],A](ma:M[A])(implicit a:Applicative[M]){

    def ~>[B](mb: M[B]):M[B] = a(a(a.pure((_:A) => (b:B) => b), ma),mb)
    def andKeep[B](mb: M[B]):M[B] = ~>(mb)

    def <~[B](mb: M[B]):M[A] = a(a(a.pure((a:A) => (_:B) => a), ma),mb)
    def keepAnd[B](mb: M[B]):M[A] = <~(mb)

    def <~>[B,C](mb: M[B])(implicit witness: <:<[A,B => C]): M[C] = apply(mb)
    def apply[B,C](mb: M[B])(implicit witness: <:<[A,B => C]): M[C] = a(a.map(ma,witness),mb)
    GeruzoniAnsasu
        46
    GeruzoniAnsasu  
       2021-01-20 20:47:07 +08:00
    std 是 stl 的命名空间

    而 stl 是 standard TEMPLATE library 的缩写,标准库本来就是为了写成模板才写成这个样子的。

    大多数语言的标准库:为了方便我们的使用者快速造车,我们先把 IO / 文件系统 / 网络库的轮子造好
    c++的标准库: 卧槽我发现我们发明的模板好像能搞些骚操作,让我尝试实现一套无类型的数据结构



    所以说这套库的意义和场景都远远不能覆盖实际开发,千万不要为了模仿 stl 把自己的代码搞得不伦不类
    SmartKeyerror
        47
    SmartKeyerror  
       2021-01-20 21:35:56 +08:00
    看到有人说在 C++里面使用 C 字符串和数组我就放心了[手动狗头]。
    levelworm
        48
    levelworm  
       2021-01-20 21:44:48 +08:00 via Android
    我觉得 vector 和 string 还是要比 C 风格的要好些了吧?
    laminux29
        49
    laminux29  
       2021-01-20 21:45:37 +08:00
    std 里的东西,有些很好,比如各种算法库;但有些又不一定好,比如 vector,脱裤子放屁做了很多不需要的功能。

    根据自己的需求,合理选择这些东西,才是正解。
    codyfeng
        50
    codyfeng  
       2021-01-20 21:51:02 +08:00
    @laminux29 #49 怎么会,std::vector 是 STL 少数几个用起来不用想太多的 container 了,其他 set 、unordered_set 、map 、unordered_map 每次用之前我都得想一下他的特性、实现和性能。记得 Bjarne Stroustrup 曾经提过,如果不知道要用什么 container,就用 std::vector 。
    travo
        51
    travo  
       2021-01-20 22:03:08 +08:00   ❤️ 1
    这恰恰说明了 C++这门语言很糟糕。
    工具是为了干活,但一种工具如果极其晦涩难用,就该换工具了。
    --------------------------------------------------
    在写 C++的时候,不小心点进 std 标准库的.h 头文件,只是看了一眼它的源代码。
    我去,一堆的 template 操作,一堆的__下划线,一堆的...变参。。。
    仿佛进入了另外一个世界,C++的水真深啊。
    我想如果看懂 std 源码,我觉得差不多也就学成了吧。
    mxalbert1996
        52
    mxalbert1996  
       2021-01-20 22:17:14 +08:00 via Android
    @myid 我觉得可能只有你一个人觉得 C 风格字符串比 std::string 更易懂。
    agagega
        53
    agagega  
       2021-01-20 22:38:16 +08:00 via iPhone   ❤️ 2
    标准库里面的实现当然是在填坑所以代码复杂..而且标准本身可能有些细节作为普通用户也没注意到(比如 iostream 的 api 本身就很复杂)另外还有 std::function 这种本身就需要一点 C++的魔法才能学会的东西。

    其实你去看其他大一点的开源项目,核心逻辑可能你都懂,但代码看着还是难受,因为大量都是在处理你可能根本没想到的特殊情况。

    C++随着几个标准更新和编译器变得越来越牛逼,现在已经逐渐变得不坑了。所以不要吐槽新标准,没人想回到连模版两个尖括号都没法连着写的时代吧?
    no1xsyzy
        54
    no1xsyzy  
       2021-01-20 22:48:10 +08:00   ❤️ 1
    @myid ……你这是 C with objects
    这种做法本身倒并不是什么问题,似乎从 C++ 出来就一直很热门的做法,不过这么用的人几乎都不会说自己在用 C++,都是在说自己在用 C with objects
    “直白易懂”你在指 Golang ?

    @James369 你可能不知道,template 语法是图灵完备的。
    见过别人写的编译期筛法素数表,搞出一堆 IsPrime<3, true> IsPrime<4, false> 这种类型
    那才叫真炫技(确实毫无卵用)
    inframe
        55
    inframe  
       2021-01-20 23:13:15 +08:00
    把 C++当 java 写,比较容易统一风格
    ipwx
        56
    ipwx  
       2021-01-20 23:59:38 +08:00   ❤️ 3
    楼上一堆没写过算法吧? C++ 的模板类是所有语言里面唯一有那么强大的抽象能力,还能保持零开销的奇葩存在了。

    如果一个 virtual function 调用的开销都无法接受,只能接受 template class 的 function 进行 inline 内联场景下,你们就知道 C++ 模板的价值了。对,我说的就是 C 语言的函数指针都比不上的部分。模板特例化可以把优化运用到极致。比如快排 C 语言版 qsort 得传进去一个函数指针,有一次函数调用。而 C++ 的 std::sort 完全可以内联掉比较器

    再比如多维张量中,所有维度都已知长度的小张量可以在堆上分配内存,而有些维度未知长度的大张量可以使用堆内存。这样能得到更高的效率。
    liuminghao233
        57
    liuminghao233  
       2021-01-21 01:24:41 +08:00 via iPhone
    之前看了 asio 的代码头都裂开了
    jsyangwenjie
        58
    jsyangwenjie  
       2021-01-21 03:39:46 +08:00   ❤️ 1
    @myid 这几句话没一句对的。。
    neoblackcap
        59
    neoblackcap  
       2021-01-21 03:45:50 +08:00
    @yazinnnn 受 ML 系的影响更大,里面一堆函数的用法。对类型系统的推崇
    owenliang
        60
    owenliang  
       2021-01-21 09:48:22 +08:00
    个人感觉:精通现代 C++的 template 语法,难度不亚于精通主流机器学习算法的推导与实现。
    laminux29
        61
    laminux29  
       2021-01-21 10:03:57 +08:00
    @codyfeng vector 在有些情况下,会自作主张调用析构函数。
    12101111
        62
    12101111  
       2021-01-21 10:17:01 +08:00
    @ipwx rust? macro_rules! #[proc_macro]
    429839446
        63
    429839446  
       2021-01-21 10:21:44 +08:00
    @nightwitch 在 ms 的系统里会影响 abi, 混用 clang 会出警告..
    codyfeng
        64
    codyfeng  
       2021-01-21 10:38:51 +08:00 via Android
    @laminux29 原来如此,vector resize 需要重新分配空间的时候的确会发生这种情况。可以如此解决
    1 、实现 move constructor
    2 、往 vector 塞东西前 reserve

    这个不能怪 vector,即使自己管理内存,需要重新分配空间时也有同样的问题。
    hobochen
        65
    hobochen  
       2021-01-21 11:32:36 +08:00
    @ipwx 话得反过来说才对,C++是零开销语言里面抽象能力最强的;更强大的抽象能力还是得看看 functional 的那一大堆
    siyemiaokube
        66
    siyemiaokube  
       2021-01-21 11:37:45 +08:00 via iPhone
    @hobochen
    个人感觉 cpp 现在已经非常 functional 了……
    nmap
        67
    nmap  
       2021-01-21 11:40:37 +08:00
    做基础库( stl/boost 等)的人,跟做应用开发的人,不是一个 level 的。。。
    fixend
        68
    fixend  
       2021-01-21 11:45:15 +08:00
    vs 的 stl 的代码风格看起来是很难理解,
    总感觉那代码是做过代码混淆的,为了防止别人抄袭,
    我没记错的话,这库是微软买的。

    应该看 clang 的 stl 库,清晰不少。

    然后,boost 库才是真会看得怀疑人生,各种模板技巧,大量 N 层嵌套的宏。
    togou
        69
    togou  
       2021-01-21 12:09:59 +08:00
    委员会那帮人 C++ 差不行么? 不说精通 比大部分专家 怕是要好吧
    hobochen
        70
    hobochen  
       2021-01-21 13:38:45 +08:00
    @siyemiaokube 没反射(甚至连编译器反射都没有)怎么和那些 type as data 的语言比啊
    hobochen
        71
    hobochen  
       2021-01-21 13:39:03 +08:00
    @hobochen 编译期
    ipwx
        72
    ipwx  
       2021-01-21 14:09:08 +08:00
    @hobochen 你说得对
    @12101111 rust 也行嘛,是我孤陋寡闻了。
    stevefan1999
        73
    stevefan1999  
       2021-01-21 17:00:43 +08:00
    @ipwx Rust
    dyv9
        74
    dyv9  
       2021-01-21 17:11:57 +08:00
    @shunia 你觉得作者和你用的是一样的 开发工具?太天真了吧。指不定人家的工具自动化水平非常高,写两段伪码剩下的自动翻译成源代码呢。
    dyv9
        75
    dyv9  
       2021-01-21 17:27:37 +08:00
    虽然 我不懂 C++,但我觉得 既然是标准库,一定是一群人讨论后觉得这个方案是适合大部分人,能解决大部分问题的普适方案,如果你的问题很特殊,那我相信你应该已经是专家,知道怎么解决问题,并不必须依赖标准库。
    lakehylia
        76
    lakehylia  
       2021-01-21 17:40:33 +08:00
    提供出去的接口千万不要用 stl,都是泪。。。
    myid
        77
    myid  
       2021-01-21 19:16:49 +08:00
    @mxalbert1996 不是 C 风格字符串更易懂,而是当 C 风格字符串就够用了,那么就用不着 std::string 了。当 C 数组就可以了,用不着非得用 std::vector 。

    std::string 作为处理字符串的类,横向对比 Python, Java 等类似的实现,就显得很残很废很单薄。是不是?
    myid
        78
    myid  
       2021-01-21 19:20:25 +08:00
    @SmartKeyerror C++里不使用 C 字符串和 C 风格数组,是一种迷信。
    mxalbert1996
        79
    mxalbert1996  
       2021-01-21 21:46:54 +08:00 via Android
    @myid 「简单是力量的保证。直白易懂是可持久可维护的护身符。」这是你自己说的,我只能理解为你觉得 C 风格字符串比 std::string 更简单易懂。
    ipwx
        80
    ipwx  
       2021-01-22 09:42:49 +08:00
    @owenliang 噗哈哈哈哈。这个比喻

    我个人的话:template 不说精通,让我写个 stl 没压力。
    机器学习不算大牛,让我推导主流网络结构公式都没压力。我的研究方向是 deep Bayesian network
    ericgui
        81
    ericgui  
       2021-02-05 15:56:29 +08:00
    问个问题:标准库谁写的?
    paxol
        82
    paxol  
       2021-04-30 17:27:33 +08:00
    @skyworker 指的是“奇异递归模板模式”( curiously recurring template pattern,CRTP )吧?把派生类作为模板参数传递给基类
    b00tyhunt3r
        83
    b00tyhunt3r  
       2021-08-09 20:53:54 +08:00
    @ipwx
    不喜欢 rust
    但是你说的这个在 rust 是基操
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   899 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 19:53 · PVG 03:53 · LAX 11:53 · JFK 14:53
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.