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

如果有人说emacs不好,你会反驳吗?如果你不会,那你的格局够大。

不会,因为

  1. 就和有人搞不定编程一样,有人搞不定 emacs 很正常,没法要求所有人都有很强的自学能力。

  2. emacs 确实有落后的地方,我用 emacs 基本是因为习惯,说白了就是沉没成本。

比如上次知乎有人骂 JavaScript 不行,结果点进去一看原来是在不同语言通行的浮点数行为都搞不定。这种问题就完全懒得反驳。

1 个赞

这个怎么说呢,一千个读者就有一千个哈姆雷特,好与不好都是仁者见仁,智者见智的事,没必要较真去反驳

然后遇到某些问题或者紧急情况,用B憋了半天,扭头发现还是A最顺手,不得不用。哈哈……

C++比Python开发效率低这个是事实吧。业界用C++的地方大抵不是因为C++是一门很优美的语言,而是因为没有什么更好的选择。譬如游戏引擎,以及性质类似的Snapchat的增强现实滤镜,达成可接受的性能要求需要对硬件的精细控制,能做到这一点的语言并不太多。在这类应用里,光是算法Big O复杂度对了是远远不够的,同样是O(N)的算法,高度优化的C++和没优化的C++性能可以相差十倍百倍。你需要考虑数据在内存里的布局,CPU缓存效率,函数调用开销,动态分派开销,多线程锁定开销,原子操作开销,以及指令级并行(SIMD)等等等等。C++允许你微调所有这些东西来把性能推到硬件能允许的上限,同时提供了比较强的抽象能力(当然比不上LISP,但是比Java要强得多)。

1 个赞

我建议你不要进行这种自虐行为。C++基本上是C的超集,并没有人禁止你在C++里写C,如果你不喜欢写class,完全可以不写,但是仍然可以利用C++的其他特性,例如更好的类型系统。

用C实现容器和泛型算法在性能上是不可能和C++竞争的。最明显的例子就是C++的std::sort吊打qsort。这是语言的本质决定的。如果要做容器,也是一样被吊打。这是因为C缺乏用模版表达类型的能力,所以动态的数据结构不得不依赖类型擦除的指针,但是大家知道一旦你malloc一回,性能就直降两个数量级,通过指针间接访问数据,性能又降一个数量级。

2 个赞

这倒是还没有,哈哈,不过他的博客文章除了C++,倒是还有其他有趣的东西,比如《瓦而登湖》,比如书写和思考的意义。

但是没什么道理啊,你也可以不扣这些性能的东西,这样写起来就快了吧,写出来也不会比 python 慢,何乐而不为~~

好吧,也不能说没有吧,但是不是 full-featured oop.

写起来一定比Python慢啊。C++的资源是手工管理的,你可以用智能指针,容器之类的简化资源管理,但还是必须要思考对象的生命周期,并不能像Python一样完全不用管。

另外你的代码块都要多打两个花括号是不是?每行都得多打一个逗号是不是?

一般写代码的时间不超过20%吧,多数时候都是在思考怎么写代码,不是吗?

1 个赞

这不至于吧…… 一个数量级可是 10 倍诶

可以通过 C 的宏来达到类似的效果,然后写一个基于数组而非指针的 generic 的 sort。原理上感觉没啥区别,不至于上升到语言本质。

比如这样?

void sort(void *start, size_t size_of_element, size_t num_of_elements);

里面可以 malloc 一个 element 作为交换时使用的临时区域,然后就各种比较和 memcpy

1 个赞

行末有分号,代码块有花括号有利于代码阅读和parser解析。python靠缩进,自己还要用眼睛看哪些是一个代码块里的。

最近写了几行swift的代码,给swift搞服气了。定义变量都要和c、java反着来,非常难受。

std::sort的比较函数是被内联化的,所以整个排序循环里不存在额外的函数调用。qsort必须接受一个排序函数指针,每一次比较都是一个通过指针进行的间接调用。

要达到类似的效果,你得把整个qsort写成一个巨大的宏。至于大家为啥不这么做,你自己试试就知道了。

之前在另外的帖子里有人提到C项目往往喜欢使用链表。那是因为链表是C里面最容易自己做出来的动态数据结构啊。像链表这种对CPU缓存极端不友好的指针数据结构,说它慢一个数量级恐怕还不止。

3 个赞

有两种语言的 sort benchmark 嘛?这个最有说服力了

原来主要在 inline 和比较函数的调用上,之前倒是没想到这个。 不过对于使用多态的一些情况,怕是函数指针是不可避免的。

另外宏除了写起来有些难受之外,在不考虑使用编译器类型系统做神奇的事情之外,似乎功能上比不模板差吧。

如果大家都写基于指针的结构的时候,似乎没啥区别?虽然这么说可能有些杠,但是感觉这句话有些太绝对了。

你看理论上大家都是O(nlogn),但是在真实机器上完全不是一回事。

5 个赞

赞。

顺手搜了下相关文章,不仅仅是 inline/fn pointer dereference 的区别,C++ 的 sort 也不是快排,差距还是挺大的。不过 qsort 貌似也是能做到 inline 的

C 里面也有三方库实现常见容器(GitHub - tezc/sc: Common libraries and data structures for C. ),用 C++ 实现链表也是一样的问题吧,链表用的还挺多的,不只是实现简单,而是最佳选择,内存分配器的 free list 一般不都是链表实现的嘛

比较好奇那个asm是怎么弄出来的,指令边上的百分比是怎么得到的呢?

  1. 排序函数和比较函数都在一个编译单元里时,C编译器确实是可以inline的。但是正常人写程序都不会把库函数一个个拷贝出来,加上inline,再放在自己的代码一起编译吧。

  2. C的所谓容器库,就是上面我说的把所有的东西都写成宏。把应该是函数的东西写成宏在C++里是一种非常糟糕的实践。很容易造成误用。例如这个取两个值里较大一个的宏:

#define max_m(a, b, result)                     \
    if (a > b) {                                \
        result = a;                             \
    } else {                                    \
        result = b;                             \
    }

现在我这样调用

        int a = 3;
        int b = 4;
        int r;
        max_m(a, ++b, r);
        printf("%d\n", r);

猜猜结果是什么?是不是正常人写这个调用时期待的结果?

我之前提过,优秀的程序库的要求是:容易使用,不容易误用。用C很难写出这样的库来。

4 个赞