(原创)后置++在不同编译器中的行为

int  x = 0;

x = x++;

 

请问上述两行代码执行之后,x的值是什么?

有的同事说1,有的同事说0,究竟是什么呢,试试就知道。

试了三个编辑器,Intergccvc自带的cl

Intergcc得出的结果都是0vc得出的结果是1

究竟哪个对呢?

让我们再看看那两行代码,第一行不用多说,把一个变量赋值为0,第二行是由两部分组成的,一部分是一个赋值语句,也就是 operator =(),一部分是后置++操作符,也就是operator ++()

后置++的行为在c++中的标准中有明确的定义:首先,取出当前操作数(本例为x,下面均已x代替)的值,放到一个临时变量中,例如y,然后再把当前x的值加上1,然后返回那个临时变量的值,也就是y的值,这三个操作是一个原子操作,中间不能插入其他代码。所以,operator ++返回的是x未加上1之前的值。

这样答案就很明显了,按照c++标准,先取出x的值(例子中x的初值为0)放入yx加上1,这时x的值是1,把operator++返回的y的值(也就是0)赋值给x,这时,x的值就从1变成0了,由此可见,Intergcc在这个操作符的实现比VC更符合c++的标准。

operator- -() 也是得到相似的结果。

下面列出VCgcc所编译出来的这两行代码的汇编代码,可以更清楚的看出这两个编译器对后置操作符的实现。

先列出VC的,我试了vc.net 2003和最新的vc.net 2008,得到的结果是一样的。

     int x = 0;

0041138E  mov         dword ptr [x],0 ; x赋初值为0

     x = x++;

00411395  mov         eax,dword ptr [x]  ; 取出x的值,放入eax

00411398  mov         dword ptr [x],eax  ; 取出eax的值,放入x中,这两句对应的c代码是x = x,可以看出,先执行了赋值操作。

0041139B  mov         ecx,dword ptr [x] ; 取出x的值,放入ecx

0041139E  add         ecx,1 ; ecx中的值加1

004113A1  mov         dword ptr [x],ecx ; ecx中的值赋值给x,以上三句执行的是c代码更像是++x

以上就是VC编译出来的代码,按这样的代码执行,得到的结果当然是1,从上面的汇编代码可以看出,在VC的实现中,如果operation ++ operator = 一起出现时,先执行的是operator =

接下来,我们看看gcc编译出的汇编代码。

movl $0, -4(%ebp) ; x初始化为0

movl -4(%ebp), %edx ; x的值放入到edx中,edx的值就会作为opeator ++的返回值

leal -4(%ebp), %eax ; 取出x的地址,放入eax

incl (%eax) ; eax中的值加1,实际上就是对x的值加1,执行之后,x=1

movl %edx, -4(%ebp) ; edx的值赋值给x,执行之后,x=0

由此可见,gcc的实现完全符合c++标准中的实现,把x的值放入临时变量,对x1,返回临时变量的值,三步操作一口气完成,中间不夹其他操作。

总结:在operator ++ operator = 一起出现的时候,VC的实现先执行 operator =,再执行 operator ++,不符合c++标准。而gcc的实现就是符合c++标准的。当然,在实际开发时不应写这种晦涩难懂的代码,一是你不能保证这种代码在各种平台上的实现是一致的,二是维护起来也麻烦。

最后摘抄一段c++ iso文档的后置++的描述。

The value obtained by applying a postfix ++ is the value that the operand had before applying the operator.[Note: the value obtained is a copy of the original value ] The operand shall be a modifiable lvalue. The type of the operand shall be an arithmetic type or a pointer to a complete object type. After the result is noted, the value of the object is modified by adding 1 to it, unless the object is of type bool, in which case it is set to true.

<think>好的,我现在需要解释C++中的重载后置++运算符。首先,得回顾一下运算符重载的基本概念,用户可能已经了解前置++,所以重点放在后置的区别上。 后置++和前置++的主要区别在于返回值类型和参数。前置++返回的是自增后的引用,而后置++需要返回自增前的值,并且需要一个int参数来区分。这里可能需要说明为什么用哑元参数,以及函数返回对象而不是引用的原因。 接下来,要举例说明。比如,定义一个简单的类,比如Counter,然后展示如何重载后置++。代码示例要正确,语法正确,同时用中文注释解释关键点。要注意返回临时对象,以保留自增前的值。 还需要比较前置和后置的区别,特别是在性能上的考虑,因为后置++通常会产生临时对象,可能在循环中影响效率。这部分用户可能会关心实际应用中的选择建议。 另外,需要提醒用户,后置++的重载应该保持语义一致性,即模拟内置类型的行为,避免混淆。可能还需要提到何时应该重载后置++,比如当类有自然递增操作且需要支持两种形式时。 检查是否有遗漏点,比如参数列表中的int,返回类型为const对象以防止连续使用后置++,如obj++++这种操作,虽然合法但可能不符合预期,所以返回const可以避免问题。 最后,总结关键点,确保用户理解语法、参数、返回值和性能影响。结构要清晰,分步骤解释,确保用户能一步步理解如何实现和使用重载后置++。</think>在C++中,重载后置递增运算符(`operator++`)需要理解其与前置递增的差异和实现要点。以下是分步说明: --- ### 一、基础语法 后置++的重载需满足: 1. **返回自增前的值**(与前置++返回新值相反) 2. **添加哑元参数`int`**(仅用于区分前置/后置,无实际用途) 3. **返回类型为`const`对象**(防止连续后置++导致的未定义行为) 语法格式: ```cpp ClassName operator++(int); ``` --- ### 二、代码示例 假设有一个`Counter`类: ```cpp class Counter { private: int count; public: Counter(int n = 0) : count(n) {} // 前置++:返回自增后的引用 Counter& operator++() { ++count; return *this; } // 后置++:返回自增前的临时对象 const Counter operator++(int) { Counter temp = *this; // 保存原值 ++count; // 执行自增 return temp; // 返回原值 } int get() const { return count; } }; ``` --- ### 三、关键区别 | 特性 | 前置++ (`++obj`) | 后置++ (`obj++`) | |---------------------|-------------------------|---------------------------| | **参数** | 无 | 带`int`哑元参数 | | **返回值类型** | 引用 (`ClassName&`) | 常量对象 (`const ClassName`) | | **返回内容** | 自增后的对象 | 自增前的临时对象 | | **性能** | 无临时对象,效率更高 | 生成临时对象,效率略低 | --- ### 四、使用场景 1. **后置++适用场景**:需要先使用原值再自增时 ```cpp Counter a(5); Counter b = a++; // b=5, a=6 ``` 2. **前置++更高效**:在循环中优先使用`++i` ```cpp for (int i=0; i<10; ++i) { ... } ``` --- ### 五、注意事项 1. **避免连续后置++**:返回`const`对象防止`obj++++`(语义不明确) 2. **保持语义一致性**:后置++应模拟`int`类型的自增行为 3. **哑元参数无实际作用**:仅用于编译器区分重载 --- 通过以上步骤,您可以正确重载后置++运算符,同时理解其与前置++的差异和适用场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值