当前位置:编程学习 > wap >>

如何提高C++的效率

自从七十年代C语言诞生以来,一直以其灵活性、高效率和可移植性为软件开发人员所钟爱,成为系统软件开发的首选工具。而C++作为C语言的继承和发展,不仅保留了C语言的高度灵活、高效率和易于理解等诸多优点,还包含了几乎所有面向对象的特征,成为新一代软件系统构建的利器。

相对来说,C语言是一种简洁的语言,所涉及的概念和元素比较少,主要是:宏(macro)、指针(pointer)、结构(struct)、函数(function)和数组(array),比较容易掌握和理解。而C++不仅包含了上面所提到的元素,还提供了私有成员(private members)、公有成员(public members)、函数重载(function overloading)、缺省参数(default parameters)、构造函数、析构函数、对象的引用(references)、操作符重载(operator overloading)、友元(friends)、模板(templates)、异常处理(exceptions)等诸多的要素,给程序员提供了更大的设计空间,同时也增加了软件设计的难度。

C语言之所以能被广泛的应用,其高效率是一个不可忽略的原因,C语言的效率能达到汇编语言的80%以上,对于一种高级语言来说,C语言的高效率就不言而喻了。那么,C++相对于C来说,其效率如何呢?实际上,C++的设计者stroustrup要求C++效率必须至少维持在与C相差5%以内,所以,经过精心设计和实现的C++同样有很高的效率,但并非所有C++程序具有当然的高效率,由于C++的特殊性,一些不好的设计和实现习惯依然会对系统的效率造成较大的影响。同时,也由于有一部分程序员对C++的一些底层实现机制不够了解,就不能从原理上理解如何提高软件系统的效率。

本文主要讨论两个方面的问题:第一,对比C++的函数调用和C函数调用,解析C++的函数调用机制;第二,例举一些C++程序员不太注意的技术细节,解释如何提高C++的效率。为方便起见,本文的讨论以下面所描述的单一继承为例(多重继承有其特殊性,另作讨论)。 

class X
{
public:
virtual ~X(); //析构函数
virtual void VirtualFunc(); //虚函数
inline int InlineFunc() { return m_iMember}; //内联函数
void NormalFunc(); //普通成员函数
static void StaticFunc(); //静态函数
private:
int m_iMember;

};

class XX: public X
{
public:
XX();
virtual ~XX();
virtual void VirtualFunc();
private:
String m_strName;
int m_iMember2;

};
 

C++的的函数分为四种:内联函数(inline member function)、静态成员函数(static member function)、虚函数(virtual member function)和普通成员函数。

内联函数类似于C语言中的宏定义函数调用,C++编译器将内联函数的函数体扩展在函数调用的位置,使内联函数看起来象函数,却不需要承受函数调用的开销,对于一些函数体比较简单的内联函数来说,可以大大提高内联函数的调用效率。但内联函数并非没有代价,如果内联函数体比较大,内联函数的扩展将大大增加目标文件和可运行文件的大小;另外,inline关键字对编译器只是一种提示,并非一个强制指令,也就是说,编译器可能会忽略某些inline关键字,如果被忽略,内联函数将被当作普通的函数调用,编译器一般会忽略一些复杂的内联函数,如函数体中有复杂语句,包括循环语句、递归调用等。所以,内联函数的函数体定义要简单,否则在效率上会得不偿失。

静态函数的调用,如下面的几种方式: 

X obj; X* ptr = &obj;
obj.StaticFunc();
ptr->StaticFunc();
X::StaticFunc(); 
将被编译器转化为一般的C函数调用形式,如同这样: mangled_name_of_X_StaticFunc();
//obj.StaticFunc();
mangled_name_of_X_StaticFunc();
// ptr- >StaticFunc();
mangled_name_of_X_StaticFunc();
// X::StaticFunc(); 

mangled_name_of_X_StaticFunc()是指编译器将X::StaticFunc()函数经过变形(mangled)后的内部名称(C++编译器保证每个函数将被mangled为独一无二的名称,不同的编译器有不同的算法,C++标准并没有规定统一的算法,所以mangled之后的名称也可能不同)。可以看出,静态函数的调用同普通的C函数调用有完全相同的效率,并没有额外的开销。

普通成员函数的调用,如下列方式: 

X obj; X* ptr = &obj;
obj.NormalFunc();
ptr->NormalFunc(); 
将被被编译器转化为如下的C函数调用形式,如同这样。 mangled_name_of_X_NormalFunc(&obj);
//obj.NormalFunc();
mangled_name_of_X_NormalFunc(ptr);
// ptr- >NormalFunc(); 
www.zztarena.com 
可以看出普通成员函数的调用同普通的C调用没有大的区别,效率与静态函数也相同。编译器将重新改写函数的定义,增加一个const X* this参数将调用对象的地址传送进函数。

虚函数的调用稍微复杂一些,为了支持多态性,实现运行时刻绑定,编译器需要在每个对象上增加一个字段也就是vptr以指向类的虚函数表vtbl。

虚函数的多态性只能通过对象指针或对象的引用调用来实现,如下的调用: 

X obj;
X* ptr = &obj; X& ref = obj;
ptr->VirtualFunc();
ref.VirtualFunc(); 

将被C++编译器转换为如下的形式。 

( *ptr->vptr[2] )(ptr);
( *ptr->vptr[2] )(&ref); 

其中的2表示VirtualFunc在类虚函数表的第2个槽位。可以看出,虚函数的调用相当于一个C的函数指针调用,其效率也并未降低。

由以上的四个例子可以看出,C++的函数调用效率依然很高。但C++还是有其特殊性,为了保证面向对象语义的正确性,C++编译器会在程序员所编写的程序基础上,做大量的扩展,如果程序员不了解编译器背后所做的这些工作,就可能写出效率不高的程序。对于一些继承层次很深的派生类或在成员变量中包含了很多其它类对象(如XX中的m_strName变量)的类来说,对象的创建和销毁的开销是相当大的,比如XX类的缺省构造函数,即使程序员没有定义任何语句,编译器依然会给其构造函数扩充以下代码来保证对象语义的正确性: 

XX::XX()
{
// 编译器扩充代码所要做的工作

1、调用父类X的缺省构造函数
2、设定vptr指向XX类虚函数表
3、调用String类的缺省构造函数构造m_strName
};
 

所以为了提高效率,减少不必要的临时对象的产生、拖延暂时不必要的对象定义、用初始化代替赋值、使用构造函数初始化列表代替在构造函数中赋值等方法都能有效提高程序的运行效率。以下举例说明:

1、 减少临时对象的生成。如以传送对象引用的方式代替传值方式来定义函数的参数,如下例所示,传值方式将导致一个XX临时对象的产生 

效率不高的做法 高效率做法
void Function( XX xx ) void Function( const XX& xx )
{{
//函数体 //函数体 
}} 
2、 拖延暂时不必要的对象定义。在C中要将所有的局部变量定义在函数体头部,考虑到C++中对象创建的开销,这不是一个好习惯。如下例,如果大部分情况下bCache为"真",则拖延xx的定义可以大大提高函数的效率。 效率不高的做法高效率做法
void Function( bool bCache )void Function( bool bCache )
{{
//函数体//函数体 
XX xx;if( bCache )
if( bCache ) {// do something without xx
{return;
// do something without xx}
return; 
}
//对xx进行操作XX xx;
//对xx进行操作

return;return;
}} 
3、 可能情况下,以初始化代替先定义后赋值。如下例,高效率的做法会比效率不高的做法省去了cache变量的缺省构造函数调用开销。 效率不高的做法高效率做法
void Function( const XX& xx )void Function( const XX& xx )
{{
XX cache; XX cache = xx; 
cache = xx ; 
}} 
4、 在构造函数中使用成员变量的初始化列表代替在构造函数中赋值。如下例,在效率不高的做法中,XX的构造函数会首先调用m_strName的缺省构造函数,再产生一个临时的String object,用空串""初始化临时对象,再以临时对象赋值(assign)给m_strName,然后销毁临时对象。而高效的做法只需要调用一次m_strName的构造函数。 效率不高的做法高效率做法
XX::XX()XX::XX() : m_strName( "" )
{{
m_strName = ""; …
… 
}} 
类似的例子还很多,如何写出高效的C++程序需要实践和积累,但理解C++的底层运行机制是一个不可缺少的步骤,只要平时多学习和思考,编写高效的C++程序是完全可行的。 --------------------编程问答-------------------- string x = "Hello, World!";
这一行C++代码背后有多少函数调用恐怕很多有经验的C++程序员都搞不清楚。
C++现在属于鸡肋技术。系统级编程基本还是用C,应用级编程C#,Java等更优雅。
Linus Torvolds也抨击C++,他的抨击不是没道理的。
QT是一个很好的例子,它的Signal/Slot相比传统的函数调用是非常低效的,如果程序中用了Signal/Slot,楼主提到的这些优化都毫无意义。当然编写QT库本身还是需要优化技术的。
总之如果需要优雅的话就不要让程序员关心太多的底层细节,如果要效率的话就不要向程序员隐藏太多的底层细节,显然C++是两边都没做好。

所以说如果有更有意义的事去做的话,不要花时间在优化C++代码上。 --------------------编程问答-------------------- 这排版~~~~~~~~~~~~~~· --------------------编程问答-------------------- 好文章,谢谢 --------------------编程问答-------------------- 推荐在乎C++效率的人看看Efficient C++ Performance Programming Techniques,看完什么都明白了;) --------------------编程问答-------------------- 虽然不太懂,但可以看出楼主很用心。 --------------------编程问答-------------------- --------------------编程问答-------------------- 硬着头皮看完的 --------------------编程问答-------------------- 努力地看完 --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 很好,O(∩_∩)O谢谢 --------------------编程问答-------------------- C++是个高效的语言 --------------------编程问答-------------------- 楼主提到的4个提高效率的方面, 和虚函数比起来都是浮云. --------------------编程问答-------------------- 说个笑话,
曾经有个问题。
为什么多态会导致C++变得没有效率?
答:因为多态会影响cpu pipeline的效率,因为相比顺序执行的代码,
多态会导致缓存命中率低。

--------------------编程问答--------------------
引用 1 楼 foundersg 的回复:
string x = "Hello, World!";
这一行C++代码背后有多少函数调用恐怕很多有经验的C++程序员都搞不清楚。
C++现在属于鸡肋技术。系统级编程基本还是用C,应用级编程C#,Java等更优雅。
Linus Torvolds也抨击C++,他的抨击不是没道理的。
QT是一个很好的例子,它的Signal/Slot相比传统的函数调用是非常低效的,如果程序中用了Signal/……


不把时间花在优化C++代码上,和没有能力优化C++代码是有区别的。 --------------------编程问答-------------------- 去看看≪深入理解计算机系统≫是怎么优化程序的。 --------------------编程问答-------------------- --------------------编程问答-------------------- 刚刚学完c语言,现在开始接触c++,看了这篇文章之后,我想会对我学习c++有帮助的,谢谢楼主了! --------------------编程问答-------------------- 还不错 --------------------编程问答-------------------- --------------------编程问答-------------------- 不知道,呵呵 --------------------编程问答-------------------- --------------------编程问答-------------------- 主要是算法用的好! --------------------编程问答-------------------- 楼主辛苦了。 --------------------编程问答-------------------- j56t --------------------编程问答-------------------- 还不错的总结 --------------------编程问答-------------------- 学习加围观...现在懒人越来越多.所以lz的贴值得支持. --------------------编程问答-------------------- --------------------编程问答-------------------- 收藏,还是很看好C++的 --------------------编程问答-------------------- 楼主 辛苦了  --------------------编程问答-------------------- 灌水的太多,按这么说用win32汇编写的windows程序的效率和c++都差不多了。
都是调用api来着啊除了在string方面好点外 --------------------编程问答-------------------- 虽然不太懂,但可以看出楼主很用心。 --------------------编程问答-------------------- Efficient C++ Performance Programming Techniques

顶这个! --------------------编程问答-------------------- 排版实在是太乱了。 --------------------编程问答-------------------- bucuobucuobucuo --------------------编程问答-------------------- Learning it~ Thank you!! --------------------编程问答-------------------- string x = "Hello, World!";
的解读要分时间段.如果读的是5年前的书,基本上其解读是有错误的.
另外,操作系统级别用C,应用级编程C#,Java等,但还有介于这中间的一层,如游戏引擎,则必须要在两者之间找到一个平衡点.

引用 1 楼 foundersg 的回复:
string x = "Hello, World!";
这一行C++代码背后有多少函数调用恐怕很多有经验的C++程序员都搞不清楚。
C++现在属于鸡肋技术。系统级编程基本还是用C,应用级编程C#,Java等更优雅。
Linus Torvolds也抨击C++,他的抨击不是没道理的。
QT是一个很好的例子,它的Signal/Slot相比传统的函数调用是非常低效的,如果程序中用了Signal/……
--------------------编程问答-------------------- --------------------编程问答--------------------
引用 17 楼 wandaoyongshi 的回复:
不把时间花在优化C++代码上,和没有能力优化C++代码是有区别的。


顶这句话 --------------------编程问答-------------------- 刚接触C++,感觉挺多不懂的 --------------------编程问答-------------------- 刷分刷分刷分刷分刷分刷分刷分刷分刷分刷分刷分刷分 --------------------编程问答-------------------- 内容出自effective c++ --------------------编程问答-------------------- 还有深度探索c++对象模型 --------------------编程问答-------------------- 马克一个 --------------------编程问答-------------------- 好多,头都看大了。。 --------------------编程问答-------------------- 楼主写得太好了。 --------------------编程问答-------------------- 该学习的还是要学习,虽然排版很让人蛋疼,还是看完了! --------------------编程问答-------------------- 每天回帖即可获得10分可用分! --------------------编程问答-------------------- 估计我层次还没到,不是很懂.. --------------------编程问答-------------------- mark~~ --------------------编程问答--------------------
引用楼主 zztarena 的回复:
自从七十年代C语言诞生以来,一直以其灵活性、高效率和可移植性为软件开发人员所钟爱,成为系统软件开发的首选工具。而C++作为C语言的继承和发展,不仅保留了C语言的高度灵活、高效率和易于理解等诸多优点,还包含了几乎所有面向对象的特征,成为新一代软件系统构建的利器。

相对来说,C语言是一种简洁的语言,所涉及的概念和元素比较少,主要是:宏(macro)、指针(pointer)、结构(struct)、……


我看你才是鸡肋 --------------------编程问答-------------------- --------------------编程问答-------------------- 太深奥 本人菜鸟级只能看热闹 --------------------编程问答-------------------- 的确,现在的C++是属于鸡肋技术 --------------------编程问答-------------------- 我也看不明白啊~太深了~不过我确实觉得C#、C++和C其实没什么区别吧。。。只是在原来的基础上升级了而已啊。。。 --------------------编程问答-------------------- =。=
以为是提问的
原来是解决问题的 --------------------编程问答-------------------- 有点复杂 --------------------编程问答-------------------- 做c++优化还是有效果的吧。 --------------------编程问答-------------------- 很不错,值得借鉴 --------------------编程问答-------------------- --------------------编程问答-------------------- 好文章,写的比较清楚 --------------------编程问答-------------------- --------------------编程问答-------------------- 决定放弃C++,去学JAVE --------------------编程问答-------------------- 挺喜欢c++的,但是现在确实有点为C++的前景担忧啊,希望新的标准可以给c++带来好的未来吧。顶一个 --------------------编程问答-------------------- 非常不错的思路! --------------------编程问答-------------------- 在构造函数里的赋值操作有时候会被编译器优化为初始化列表。 --------------------编程问答-------------------- 还不错 --------------------编程问答--------------------    我实在太菜了   学习中。。。 --------------------编程问答-------------------- 非常不错的思路! --------------------编程问答-------------------- 没有深入理解过C++,准备学C的,看看 --------------------编程问答-------------------- 一直不太懂这个问题,这次真的谢谢楼主 --------------------编程问答-------------------- 真心复杂 --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 这个点,以前一直比较模糊,LZ这样清晰地贴出来,没一点都看得透彻明白,Lz辛苦啦……总结得很好,需要慢慢理解…… --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 认知级别有点低. 你需要的是视野的提升. --------------------编程问答--------------------
引用 1 楼 foundersg 的回复:
string x = "Hello, World!";
这一行C++代码背后有多少函数调用恐怕很多有经验的C++程序员都搞不清楚。
C++现在属于鸡肋技术。系统级编程基本还是用C,应用级编程C#,Java等更优雅。
Linus Torvolds也抨击C++,他的抨击不是没道理的。
QT是一个很好的例子,它的Signal/Slot相比传统的函数调用是非常低效的,如果程序中用了Signal/……


c++技术是java和c#思想的根源。。
写性能NB的游戏,就明白c++的作用了。。 --------------------编程问答--------------------
引用 1 楼 foundersg 的回复:
string x = "Hello, World!";
这一行C++代码背后有多少函数调用恐怕很多有经验的C++程序员都搞不清楚。
C++现在属于鸡肋技术。系统级编程基本还是用C,应用级编程C#,Java等更优雅。
Linus Torvolds也抨击C++,他的抨击不是没道理的。
QT是一个很好的例子,它的Signal/Slot相比传统的函数调用是非常低效的,如果程序中用了Signal/S……


只要你不是拿c++标准还没有统一的年代来说事,这一行代码的调用就是等同于string x("hello, world")。就这么简单,很多人只是自己把自己给绕晕了而已。

楼主介绍的这些东西其实都属于非常基本的了,其实性能这个东西,从算法上的优化才是根本,然后就是多线程下的优化,这个也是个大难题。

--------------------编程问答-------------------- 还不错 值得看看 --------------------编程问答-------------------- --------------------编程问答-------------------- 刚开始学C++,看不懂 --------------------编程问答-------------------- --------------------编程问答-------------------- 现在开始接触c++ --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 要下载东西还要积分。。 --------------------编程问答-------------------- 不错的文章。。学习中。。。。。。。。。 --------------------编程问答--------------------
引用 2 楼 lihanbing 的回复:
这排版~~~~~~~~~~~~~~·

木排版 --------------------编程问答-------------------- --------------------编程问答-------------------- 很好很强大 --------------------编程问答-------------------- 对我学c++的有帮助。 --------------------编程问答-------------------- 辛苦了 谢谢 有很大的帮助~ --------------------编程问答-------------------- 现在的ide异常的强大,在编译时会很大一部分对你代码进行优化。所以技术如果没得很NB的话,建议大家不要想着优化。当然从程序结构上优化会收获很多东西。
补充:移动开发 ,  Qt
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,