优先使用前缀操作符
来源:互联网 发布:天鹰行动23.d vb 编辑:程序博客网 时间:2024/06/04 08:26
也许从开始接触C/C++程序的那天起,就记住了前缀和后缀运算,知道了++的前缀形式是“先加再用”,后缀形式是“先用再加”。前缀和后缀运算是C和C++语言中的基本运算,它们具有类似的功能,区别也很细微,主要体现在运行效率上。分析下面的代码片段:
int n=0, m=0;
n = ++m; /*m先加1, 之后赋给n*/
cout << n << m; /*结果:1 1*/
在这个例子中,赋值之后,n等于1,因为它是在将m赋予n之前完成的自增操作。再看下面的代码:
int n=0, m=0;
n = m++; /*先将m赋于n, 之后m加1*/
cout << n << m; /*结果:0 1*/
这个例子中,赋值之后,n等于0,因为它是先将m赋予n,之后m再加1的。为了更好地理解前缀操作符和后缀操作符之间的区别,可以查看这些操作的反汇编代
码。即使不了解汇编语言,也可以很清楚地看到二者之间的区别,注意inc指令出现的位置:
/* 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*/
/*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*/
从汇编代码可以看出,两者采取了相同的操作,只是顺序稍有不同而已。但是,前缀操作符的效率要优于后缀操作符,这是因为在运行操作符之前编译器需要建立一个临时的对象,而这还要从函数重载说起。重载函数间的区别取决于它们在参数类型上的差异,但不论是自增的前缀还是后缀,都只有一个参数。为了解决这个语言问题,C++规定后缀形式有一个int类型的参数,当函数被调用时,编译器传递一个0作为int类型参数的值给该函数:
//成员函数形式的重载
< Type > ClassName :: operator ++ ( ); // 前缀
< Type > ClassName :: operator ++ ( int ); // 后缀
// 非成员函数形式的重载
< Type > operator ++ (ClassName & ); // 前缀
< Type > operator ++(ClassName &,int); // 后缀
在实现中,后缀操作会先构造一个临时对象,并将原对象保存,然后完成自增操作,最后将保存对象原值的临时对象返回。代码如下所示:
ClassName & ClassName::operator++()
{
ClassAdd (1); //increment current object
return *this; //return by reference the current object
}
ClassName ClassName::operator++(int unused)
{
ClassName temp(*this); //copy of the current object
ClassAdd (1); //increment current object
return temp; //return copy
}
由于前缀操作省去了临时对象的构造,因此它在效率上优于后缀操作。不过,在应用到整型和长整型的操作时,前缀和后缀操作在性能上的区别通常是可以忽略的。但对于用户自定义类型,这还是非常值得注意的。当然就像80-20规则告诉我们的那样,如果在80-20规则:一个典型的程序将花去 80% 的时间仅仅运行 20% 的代码。一个很大的程序里,程序数据结构和算法不够优秀,它所能带来的效率提升也是微不足道的,不能使大局有所改变。但是既然它们有差异,我们为什么不在必要的时候采用更有效率的呢?
请记住:
int n=0, m=0;
n = ++m; /*m先加1, 之后赋给n*/
cout << n << m; /*结果:1 1*/
在这个例子中,赋值之后,n等于1,因为它是在将m赋予n之前完成的自增操作。再看下面的代码:
int n=0, m=0;
n = m++; /*先将m赋于n, 之后m加1*/
cout << n << m; /*结果:0 1*/
这个例子中,赋值之后,n等于0,因为它是先将m赋予n,之后m再加1的。为了更好地理解前缀操作符和后缀操作符之间的区别,可以查看这些操作的反汇编代
码。即使不了解汇编语言,也可以很清楚地看到二者之间的区别,注意inc指令出现的位置:
/* 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*/
/*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*/
从汇编代码可以看出,两者采取了相同的操作,只是顺序稍有不同而已。但是,前缀操作符的效率要优于后缀操作符,这是因为在运行操作符之前编译器需要建立一个临时的对象,而这还要从函数重载说起。重载函数间的区别取决于它们在参数类型上的差异,但不论是自增的前缀还是后缀,都只有一个参数。为了解决这个语言问题,C++规定后缀形式有一个int类型的参数,当函数被调用时,编译器传递一个0作为int类型参数的值给该函数:
//成员函数形式的重载
< Type > ClassName :: operator ++ ( ); // 前缀
< Type > ClassName :: operator ++ ( int ); // 后缀
// 非成员函数形式的重载
< Type > operator ++ (ClassName & ); // 前缀
< Type > operator ++(ClassName &,int); // 后缀
在实现中,后缀操作会先构造一个临时对象,并将原对象保存,然后完成自增操作,最后将保存对象原值的临时对象返回。代码如下所示:
ClassName & ClassName::operator++()
{
ClassAdd (1); //increment current object
return *this; //return by reference the current object
}
ClassName ClassName::operator++(int unused)
{
ClassName temp(*this); //copy of the current object
ClassAdd (1); //increment current object
return temp; //return copy
}
由于前缀操作省去了临时对象的构造,因此它在效率上优于后缀操作。不过,在应用到整型和长整型的操作时,前缀和后缀操作在性能上的区别通常是可以忽略的。但对于用户自定义类型,这还是非常值得注意的。当然就像80-20规则告诉我们的那样,如果在80-20规则:一个典型的程序将花去 80% 的时间仅仅运行 20% 的代码。一个很大的程序里,程序数据结构和算法不够优秀,它所能带来的效率提升也是微不足道的,不能使大局有所改变。但是既然它们有差异,我们为什么不在必要的时候采用更有效率的呢?
请记住:
对于整型和长整型的操作,前缀操作和后缀操作的性能区别通常是可以忽略的。对于用户自定义类型,优先使用前缀操作符。因为与后缀操作符相比,前缀操作符因为无须构造临时对象而更具性能优势。
转自《编写高质量代码——改善C++程序的150个建议》
阅读全文
0 0
- 优先使用前缀操作符
- 改善C++ 程序的150个建议学习之建议12:优先使用前缀操作符
- 总是优先使用++、--的前缀形式
- C++编程规范之28:优先使用++和—的标准形式。优先调用前缀形式
- 《优先队列》使用及操作符重载——C++
- RxJava的懒加载,慎重使用自定义操作符,优先考虑内置操作符
- RxJava的懒加载,慎重使用自定义操作符,优先考虑内置操作符
- 前缀操作符和后缀操作符的重载
- 操作符重载,区分前缀与后缀操作符
- 深度解析前缀操作符与后缀操作符
- 3. 在 as 和 强制类型转换之间,优先使用 as 操作符。
- 操作符++/--的前缀形式与后缀形式的区别
- 重载前缀和后缀自增操作符
- ++与 -- 操作符前缀形式与后缀形式的区别
- 使用的控件前缀
- SQLSERVER 使用 N 前缀
- 蓝桥杯 前缀表达式(字符操作)
- 优先队列的操作
- 浏览过的博客记录
- 取消与关闭
- MYSQL数据库引擎
- 【Java8】 行为化参数
- 【自组织网】【笔记】之OPNET常见问题
- 优先使用前缀操作符
- python: 字符串占位符的"{0:2}"
- 机器学习之用 Python 从零实现贝叶斯分类器
- mach-o格式分析
- Objective-C:探索block(二)
- 计算机导论学习第一课笔记
- [FUNC]查看数组内容
- 深度学习:目标检测-RCNN学习笔记:SSD:Single Shot MultiBox Detector
- POJ 2408 Anagram Groups 笔记