任何时候都适用的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/

版权:本文版权归作者和博客园共有

转载:欢迎转载,为了保存作者的创作热情,请按要求【转载】

要求:未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任
原文链接: https://www.cnblogs.com/lijian2010/archive/2010/12/06/1897798.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/18353

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月7日 下午7:09
下一篇 2023年2月7日 下午7:10

相关推荐