任何时候都适用的20个C++技巧 <9-11> 性能的提升

Nine to 11: Performance Enhancements

下面所列出的是三个相当简单但又不是很常见的技术,在不牺牲程序可读性、不修改程序设计的前提下,提高程序的性能。例如,程序员往往不太清楚,只是简单的对数据成员进行重新排序就可以大大减少它的大小。这种优化可以提高性能,如果应用程序使用到了这些对象的数组,效果尤其明显。此外,我们还将学习前缀和后缀操作符之间的差异;在重载操作符中,这是一个很重要的问题。最后,我们将学习一些消除临时对象的创建的方法。

技巧9:类成员对齐方式的优化

  只需改变类成员的声明顺序就可以改变这个类的大小:

  
    
struct A
{
bool a;
int b;
bool c;
};
/* sizeof (A) == 12 */

  在我的机器上,sizeof (A) 等于12。结果看起来非常的出乎意料,因为A的成员大小之和仅仅是6个字节,多余的6个字节来自何方呢?编译器在每个bool类型成员的后面插入了各插入三个填充字节,使得它四字节边界对齐。你可以按照下面的方式重新组织数据成员减少A的大小:

  
    
struct B
{
bool a;
bool c;
int b;
};
// sizeof (B) == 8

  这次编译器只是在成员c的后面插入两个填充字节。因为b占4字节,它自然就word边界对齐,而不需要额外的填充字节。

 

技巧10:明确前缀后缀操作符之间的差异

  内置的++操作符可以放在操作数的两边:

  
    
int n = 0 ;
++ n; /* 前缀 */
n
++ ; /* 后缀 */

  你一定知道前缀操作符首先改变操作数,然后再使用它的值。比如:

  
    
int n = 0 , m = 0 ;
n
= ++ m; /* first increment m, then assign its value to n */
cout
<< n << m; /* display 1 1 */

  在这个例子中,在赋值之后,n等于1;因为它是在将m赋予n之前完成的自增操作。

  
    
int n = 0 , m = 0 ;
n
= m ++ ; /* first assign m's value to n, then increment m */
cout
<< n << m; /* display 0 1 */

  在这个例子中,赋值之后,n等于0;因为它是先将m赋予n,之后m再加1。

  为了更好的理解前缀操作符和后缀操作符之间的区别,我们可以查看这些操作的反汇编代码。即使你不了解汇编语言,你也可以很清楚地看到二者之间的区别,注意inc指令出现的位置:

  
    
/*disassembly of the expression: m=n++ ; */
mov ecx, [ebp-0x04] /*store n ' s value in ecx register*/
mov [ebp-0x08], ecx /*assign value in ecx to m*/
inc dword ptr [ebp-0x04] /*increment n*/



/*disassembly of the expression: m=++n;*/
inc dword ptr [ebp-0x04] /*increment n;*/
mov eax, [ebp-0x04] /*store n
' s value in eax register*/
mov [ebp-0x08], eax /*assign value in eax to m*/

 

注:前缀操作符、后缀操作符与性能之间的联系是什么?原文作者没有说明。所以有了亚历山大同志 的疑问。在此做一下说明:当应用内置类型的操作时,前缀和后缀操作符的性能区别通常可以忽略。然而,对于用户自定义类型,后缀操作符的效率要低于前缀操作符,这是因为在运行操作符之间编译器需要建立一个临时的对象
 

技巧11:尽量消除临时对象

  在一些情况下,C++会“背着你”创建一些临时对象。一个临时对象的开销可能很大,因为它的构造和析构函数肯定会被调用。但是,在大多数情况下,您可以防止临时对象的创建。在下面的例子,一个临时对象被创建:

  
    
Complex x, y, z;
x
= y + z; /* temporary created */

  表达式y+z;将会导致一个Complex类型的临时对象的产生,这个临时对象保存着相加的结果。之后,这个临时对象被赋予x,随后销毁。临时对象的生成可以用两种方式加以避免:

  
    
Complex y,z;
Complex x
= y + z; /* initialization instead of assignment */

  在上面的例子中,y和z相加的结果直接用于对象x的构造,所以就避免了起中介作用的临时对象。或者你可以用+=代替+,同样可以达到相同的效果:

  
    
/* instead of x = y+z; */
x
= y;
x
+= z;

  虽然采用+=的这个版本不太优雅,它只有两个成员函数调用:赋值操作和+=操作。相较而言,使用+操作符则产生三次成员函数调用:临时对象的构造、对于x的拷贝构造,以及临时对象的析构!

  

// 续 任何时候都适用的20个C++技巧 <12-13>  Object-oriented Design 

作者: 凌云健笔

出处:http://www.cnblogs.com/lijian2010/

版权:本文版权归作者和博客园共有
转载:欢迎转载,为了保存作者的创作热情,请按要求【转载】
要求:未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任

你可能感兴趣的:(C++)