C++语法|++i和i++的效率问题|重载前置++运算符和重载后置++运算符

++i 和 i++
在不涉及到类的前加和后加,除了代码顺序的差异,其实在效率上来说并没有什么区别。如果加上编译器的优化,他们生成的汇编指令可能是完全相同的。但是我们今天主要就讨论这样的情况。

如果把i++比做一个函数,由于语法规则的要求,它只能把加1千的原始值,返回给主调函数。所以,在自加1之前,它需要用一个临时变量,保存自己的原始值,而构建原始原谅的这个操作就是占用内存和CPU资源的始作俑者。

如果我们的临时变量是一个类,这个构建临时对象的开销无法忽略:

重载前置 ++ 运算符

首先明确前置 ++ 运算符的

语义:它首先对对象执行自增操作,然后返回自增后的对象自身。

具体实现:由于前置 ++ 运算符直接返回自增后的对象自身,返回类型应为对象的引用。这样可以避免不必要的对象拷贝,提高效率。

class A {
public:
	int x;
	A& operator++() {
		x++;
		return *this;
	}
}

重载后置++运算符

语义:后置 ++ 运算符首先保存当前对象的状态,然后对对象执行自增操作,最后返回保存的未自增的对象状态。

具体实现:明确语义后,实现就很直观了,由于后置 ++ 运算符需要返回自增前的对象状态,因此返回类型应为对象的副本。这意味着需要创建一个对象的临时副本,并在返回前进行对象状态的保存。
我们在刚才类的基础上实现:

A operator++(int) {
	A tmp = *this;
	++*this;
	return tmp;
}

在运算符重载中,参数列表是运算符函数的一个重要组成部分。为了区分前置和后置 ++ 运算符,后置 ++ 运算符需要一个额外的 int 参数。这个参数并不实际使用,仅仅作为一个标识。

重载后置++运算符的汇编

大头来了,我们一起看看他的汇编代码:

首先是构建临时对象的汇编A tmp = *this;

mov		rax, QWORD PTR [rbp-24]
mov		eax, DWORD PTR [rax]
mov		DWORD PTR [rbp-4], eax

嗯嗯构建临时对象感觉还好,接下来是++*this;

mov		rax, QWORD PTR [rbp-24]
mov		rad, rax
call		A::operator++()

!!!他竟然调用了前加函数!
这样的话后加(i++)需要包含一个完整的前加(++i)操作,这种差异性能当然天差地别!

总结:我们总是在讨论++i和i++的性能问题,其实在很多时候,他们两个除了语法的差异外,在汇编的面前都是几条简单、直接的指令。
但是只要涉及到类,问题就完全不一样了,因为后加回包含一次完整的前加操作,如果这个类的数据及其庞大,这对效率的影响是非常大的。

热点面试题

  • 前加(++i)是左值的,这是什么意思?

前加的返回值,是一个变量的引用,该引用是可以被赋值的。例如,我们可以把2赋给前加,但是不能把2赋给后加,因为后加是右值的,如下代码:

void func_3() {
	int i = 1;
	++i = 2;
	//i++ = 2; //错误!
}
  • 如果i = 1,(++i)++应该等于多少

不建议写这样的代码,非常不方便阅读。因为它涉及到未定义行为(undefined behavior)。未定义行为意味着C++标准并未规定在这种情况下应该如何执行程序,因此不同的编译器可能会有不同的解释和处理方式。
其次,不同编译器对该代码的解释会有区别。如果只针对特定的编译器,例如GCC,他的结果是可以预期的;但是如果使用Clang和Visual Studio编译运行可能会得到不同的结果 。因为

  • GCC:在某些情况下,GCC可能会按照一定的顺序进行评估,使得结果是可以预测的,但这种行为并不受C++标准保障。
  • Clang和Visual Studio:这些编译器可能会采用不同的优化和评估策略,导致不同的结果,或者可能直接产生编译错误或运行时错误。
  • 22
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值