学C++越学越有味是怎么回事

请问慢速模式是个什么样子的?好奇。 另外,你怎么能控制我的帖子!好怒

就是一个人发帖会间隔10分钟,防止上头.

另外他是管理员, 我也是管理员 (滑稽)

1 个赞

每个语言都有自己的特点,重要的还是用语言写出满足自己需求的程序,毕竟语言只是一个工具而已。

3 个赞

哈哈确实是的。我只是觉得争论没啥意义,所以说了些废话缓解一下气氛 :crazy_face:

每个语言都有自己的特点,重要的还是用语言写出满足自己需求的程序,毕竟语言只是一个工具而已。

1 个赞

阿这…原来搞了这么一大圈,难不成是我引起的战火?? 如果是,那真的非常抱歉。

其实我也是cpp爱好者,我过去两年大学都是学cpp的,哈哈。我学c语言恰恰是最近的事情。我还发了两个帖子请教。

c很多开源项目为何重度用链表

新人如何打造一个最小最轻量,tags流(非lsp),c语言的工作环境,用于阅读linux kernel?

学c的主要原因是研究skynet时,受到云风 “用c写网络底层,用lua快速写逻辑” 这种思想的影响。 因此对用c写底层很感兴趣。比如,libevent,nginx,redis,linux kernel都是用c写的,我很想去研究他们代码。

不过这部分也是cpp的强力领域 (不会有人用纯c写上层业务吧)。 cpp的网络库我仔细研究过muduo。我发现到了底层后,cpp和c已经很像了。 比如muduo,基本没什么高级特性,就是在c的基础上,套个class,用了智能指针,用了std::function做回调. 还有用了一些基础的容器。这些并不是必不可少的东西,不过确实有效的简化代码。按照陈硕的说法, 可以把cpp当成一个better c来用。

但是有趣的是,muduo有很多地方是可以优化的,比如环形缓冲区muduo用了std::vector去实现。 它的定时器采用了std::set管理,std::function+bing做回调等。在git上有很多仿写项目,将这些部分优化掉,改成了c的写法,性能得到了提高。 所以,我觉得在接近底层的地方,cpp会越来越接近c。

我现在知道的两种观点就是 (1): better c, 可以用c++的特性简化代码,比如class,template,stl等。 (2) 纯c,Linus曾经就提到过用c的原因就是确保没有人滥用cpp的特性去捣乱,用c简单,可控。用宏虽然麻烦,指针虽然危险,但是底层才多少代码啊, libevent出来多少年了,也就修修补补。真coredump了,就gdb呗。

我还是学生,所以我没有想这么多,目前还在忙着看别人的开源项目,有什么我就学什么…话说各位大佬你们怎么看啊?

4 个赞

我觉得Very Nice.
从某种角度上来说,在抽象性与具体性之间把握平衡度是一个难题.
这才是引发这么多争论的原因吧.

唔,别想太多,我引用你的话只是为了说明那个让C的拥趸们破防的话是有一个具体的语境的,只是很遗憾看到原本颇有价值的讨论变成了各种稻草人攻击和白烂话的复读。我对于c和c++哪个好并没有什么特别的兴趣,只是看不下去这帖里那些逻辑混乱的发言所以指出这一点而已,当然,从社区的反应来看,或许我不应该指出来(笑,毕竟

image

请你不要曲解我的意思,我的确认为C++全面强于C。除非在没有C++编译器的平台上,否则基本上没有什么理由要把自己局限在纯C。

  1. C++是C的超集,多出来的东西你可以选择用还是不用。
  2. 并不存在用C能优化的C++代码(因为C代码就是C++代码)。从一个C++项目里找一些地方优化一下,无非是说明原作者在某些地方没有下大力气优化。反过来从C代码里找点地方用C++优化一下也是可以的(例如把qsort全部换成std::sort)。
  3. Linus不用C++不代表这就是对的,只是作者的个人偏好。Linus还用MicroEmacs呢,也说明MicroEmacs比GNU Emacs强么?况且Linus不用C++本身就不是真的。Linus写的潜水软件Subsurface就是用C++写的。
1 个赞
  1. 需要严格控制代码尺寸是我唯一可以想到的选择用纯C的合理理由。在操作系统核心,以及内存非常紧张的嵌入式平台上,选择用纯C,我虽然不100%赞同,但可以理解。透过C++代码看到背后的机器码,需要多年的经验,或者即便有多年的经验,也有疏忽的时候。这时C的优点是你写一行代码,机器码里必然只有你写的这行代码,不会有编译器插入的构造析构函数,不会有实例化的模板,比较容易控制机器码尺寸。之所以仍然不能100%赞同,是因为选择一个合适的C++子集在我看来依然是个更好的选择,例如Apple的核心模式驱动框架IOKit。
1 个赞

没错,我完全赞同c++比c强大。c++能做的事情远远比c要多的多。但是就底层而言,c++的功能与c高度重合。

我曾经就优化了上面说的muduo网络库,因为std::vector作为环形缓冲区性能有问题,所以我借鉴了linux kfifo写了一个。定时器管理我也改成了最小堆实现(其实最好的是linux kernel的时间轮算法)。std::function+bind用做回调接口开销据说也很大,可以改成c的void*,我没改,因为把回调接口都改了还不如直接用libevent。我改动的这些代码中,可以用c写,也可以套个class,区别不大。

c++在这个领域的功能受限与c,当然可以用.cc文件写c风格的代码。但是强制你写.c文件的一个好处在与就是减少不必要的内耗,这部分内耗正由c++强大带来的副作用。muduo作者在书中提倡使用智能指针和std::function作为回调接口,前几个月我看到搜狗开源框架workflow的作者说不应该使用std::shared_ptr,也有说c++应该像asio一样写成.hpp文件,也有说只应该在头文件暴露get_xx(),set_xx()的内联函数。那他们谁说的对呢?

我对c,c++都不怎么熟,不知道怎么说好

我并不是想说明用c去优化c++代码,而是说明在优化的过程,c++的高级特性特性逐渐被去掉。最后只剩下了c子集。也就是c++写的东西用c写是一样的。而用c的好处上个答复已经说了。

不好意思,因为限制10分钟发一次消息。所以,刚才回你的那两段冲动了。

我现在冷静下来了,仔细重看了我上面的观点,也许那只是我平常的一些思考,疑惑罢了,我真的坚信吗? ?也许我应该尝试去接受不同的观点,毕竟我现在还在上学,顶多只是看过一些开源代码,经验和见识都没有资格和你比。也许是我学习的范围太多狭隘,得出这么个结论,如果我错了,希望大佬能指正。

你的第四点建议,我很赞同,c++确实需要一个合适的子集。

1 个赞
  1. 我赞成你只使用你能够熟练掌握的C++子集。有不少人试图一口气掌握C++的所有方面,结果被它的复杂性压倒,转头成了C++黑。
  2. 我不赞成你以自己能力的局限来推断C++的局限。

这是你测量了还是你猜的?vector的均摊存取时间是O(1),无需扩容时存取时间与C数组没有任何区别,只有在需要扩容时才有内存重分配。一个设计良好的环形缓冲区应该基本不需要扩容,如果需要扩容的话,用C写的环形缓冲也得重新分配内存。

你大概不知道C++标准库提供了堆算法吧(make_heap/pop_heap)?你自己手写的堆算法基本上没有可能比标准库的实现更高效。

我的同事Eduado编写的zoo::function效能全面超越了std::function。但是是否有必要,还是那句话,你测量了吗?

用shared_ptr<>还是用作用域来进行资源管理代表了两种不同的策略。在C++里你可以根据需要来选择。但有一点可以肯定的是,这两者都比手工malloc/free要容易使用,不容易犯错。

std::vector作为Ringbuffer性能有问题,根本不用我测也不用猜,是作者在书上亲口说的,他说之所以用vector是因为 1. muduo的使用场景用于内网的网游服务器,此时吞吐量不会成为性能瓶颈。2.想把代码写简单。(大致是这样,我书暂时找不到,凭借记忆)。 不单是我,不少人研究过muduo啊,替换ringbuffer,按照书中作者的测试方法,吞吐量提升,随便网上搜下大把实例。

如果作者根本没打算花力气去优化,那根本不能说明用c++导致性能不行,换了c就能提高,对不对?

能把性能不关键的代码写得简明易懂,不失为一种选择。作者对定时器用set的态度大概也是类似的。堆函数理论上能快那么一点点,但也许不值得把代码写得更复杂。

1 个赞

额,好吧,也许我是因为空虚。。。没有实现linux kernel Timer,所以想去要撸点轮子填补下自己内心的空虚。make_heap确实比我手写最小堆要快。

std::function<>性能有问题,是我听说的,实际上怎么样,我并没有去测。我过去认为底层代码就应该够暴力: void* args+void(* func)(void*)。now我觉得你说的很对。

嗯,祝你有个好梦

没想到!!!竟然是我记错了。。。std::vector实现的并不是一个ringbuffer。其readIndex不会超过WriteIndex,而是每次插入数据时检测前面容量是否足够,然后把数据拷贝回去,我晕。所以造成性能开销的因素就是402行频繁的拷贝。

这里是我错了,两个并不是同一种数据结构。

固定页面链表: 追加数据时,不断的分配 4K大小的页面追加到链表末尾,前面读完第一页数据时就可以把那一页从链表上移走。这样既避免了频繁数据搬移也避免了频繁分配释放,不会出现内存利用不充分的情况。而外部做一个 free list来管理 4K大小的固定内存分配,又可以实现 O(1)的分配和释放,整个系统都是 O(1)的时间复杂度,比 Ring Buffer好很多。

冲浪看到的,打算去研究下。