phy0292 2017年09月27日
C++与C哪个慢,要看具体的代码
看了几篇争论C++比C慢的帖子,发现有些人给出的C++比C慢的代码并不是和原作者一样的结果,而是恰恰相反!比如我从别处复制的如下代码:

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <string>
using namespace std;
int i,j;
char cs[10001];
string cpps;
clock_t t;
void main() {
t=clock();
for (i=0;i<10;i++) {
cs[0]=0;
for (j=0;j<10000;j++) {
strcat(cs,"a");
}
}
printf(" cs %lg\n",(double)(clock()-t));
//----------------C和C++分割线-------------
t=clock();
for (i=0;i<10;i++) {
cpps="";
for (j=0;j<10000;j++) {
cpps=cpps+"a";
}
}
printf("cpps %lg\n",(double)(clock()-t));
}
// cs 125
//cpps 203

比如上面这段代码,原作者输出C语言消耗时间是125毫秒,C++消耗时间是203毫秒。
但我运行上段代码得到的结果恰恰相反,cs 200 cpps 30,反复试几次,结果差不多。如果大家不信也可以试试,但前提条件是请在Release方式下运行,不要在Debug方式下运行。如果在Debug方式下运行,结果又会反转,因为Debug方式下,标准库加了不少调试用的附加代码。
如果把上面这段代码再优化一下:

cpps=cpps+"a";

改成
cpps += "a";

或者改成
cpps.append("a");

那么C++又会快更多,结果是C 200毫秒,C++ 1毫秒,反复试几次,也就这样的数量级。
争论的帖子里都说C++的对象因为构造、析构、动态内存分配等等原因,导致C++比C慢,但结果为什么相反?而有的人连代码都没有试也随声附和,所以看问题要亲自测试亲眼所见再下结论才更科学。
然而上面这段代码初一看,感觉C无论如何也要比C++快,并且要快很多,但为什么结果相反呢,经过分析,恰恰是string的类包含了一些重要的信息才导致C++反而要快很多。

现在我分析一下原因:
在上面代码的C实现中,最耗时的是strcat函数,200毫秒的时间都是耗在这个函数上。大家都知道这个函数是把参数2的字符串追加到参数1的后面。它的实现过程是这样的,从参数1的第一个字符开始一直找到末尾的\0,然后把参数2复制到这个末尾。也就是说它每次追加前都要从第一个字符开始遍历一下参数1中的所有字符,直到找到末尾在哪。当这个字符串变得越来越长的时候,这个无谓的时间也就消耗的越来越多,实际上它用的是蛮力。而在本例中,字符串最长时有10000字节。也就是说它平均每次要遍历5000字节,请注意是平均每次。
再来看看C++标准库中string的实现,cpps += "a";它也是把后面的字符串追加到前面的string中,在追加的时候,它已经知道自己的末尾在哪里,因为它的末尾是end(),或者是begin()+size(),所以string就不用像strcat那样傻傻地从头到尾找一遍末尾在哪,而是直接把字符串追加到自己的后面。当然如果在追加后长度超出来了自己力所能及的范围,也就是追加后总长度要大于capacity()的话,那么它就会重新分配更大的内存,这就是长度动态增长,当然这会消耗时间。而在我们上面这段代码中,在第一次内循环结束后,cpps实际分配的内存已经大于等于10001字节了,在第二次内循环时,它就不用再分配内存了,因为它已经足够容纳接下来每次循环所要求的长度。那有人会说,内循环外不是有个cpps = "";吗,分配的长度不会重新缩回去吗。不用担心,不会发生这样的事,容器中分配的内存只会增长不会缩小,像cpps = ""或cpps.clear(),只是让size=0,分配的内存原样不动。所以上面的代码在第一次内循环时消耗了一点分配内存的时间,而接下来这点时间也省略掉了。
结论:实际上C++标准库中的一些设计不单单让我们方便使用,也能提升一些效率,与有些人想像的恰恰相反。

最后,建议cpps = cpps + "xxoo";这样的代码都应该写成 cpps += "xxoo";如果有很多这样的代码,或在循环中经常出现,那会提升不少效率。原因就不用我说了吧。

再最后说说c++这里一个不足的地方,刚前面说到容器分配了内存后就不会再缩小了,所以在上面的程序结束前,cpps里分配的大于10001字节的内存就一直霸占着不放手了。上面代码里cpps还是全局变量,所以只到程序运行结束,内存才会释放,这样的话,如果程序中有一次用到了100000001字节或更大,而其它时候都只是10001字节就够了,那么它自始自终要占着大于100000001字节的内存不放手!这是我一直觉得不爽的地方!

有相同的看法或不同看法的,都来说说吧!
...全文
273 点赞 收藏 17
写回复
17 条回复

还没有回复,快来抢沙发~

发动态
发帖子
C++ 语言
创建于2007-09-28

3.1w+

社区成员

24.8w+

社区内容

C++ 语言相关问题讨论,技术干货分享
社区公告
暂无公告