c ++重载+运算符不返回临时对象,为什么?

时间:2012-03-07 01:21:48

标签: c++

这是源代码:

#include<iostream>
using namespace std;

class cat{
    private:
      int a;
    public:
      cat():a(1){
         cout << "const : " << this << endl;
      }
     ~cat(){
         cout << "dest :  " << this << endl;
      }
    cat operator+(cat& rhs){
         cout << "+" << endl;
         cat x;
         x.a=a+rhs.a;
         return x;
      }
    cat operator=(const cat& rhs){
        cout << "= :  " <<this << endl;
        a=rhs.a;
        return (*this);
      }
    cat(const cat& rhs){
        cout << "copy const : " << this << endl;
        a=rhs.a;
      }
 };

 int main(){
 cat ob1;
 cat ob2;
 cat ob3;
 ob1=ob2;
 cout << "\n 1----1 \n" << endl;
 ob3=(ob1+ob2);
 cout << "\n 2----2 \n" << endl;
 cat ob4=ob1+ob2;
 cout << "\n 3----3 \n" << endl;

 }

这是输出:

const : 0x22ff20          // ob1 created
const : 0x22ff1c          // ob2 created
const : 0x22ff18          // ob3 created
= : 0x22ff20             // calling = operator 
copy const  :  0x22ff24   // return temporary object using copy constructor
dest :  0x22ff24          // temporary object is destroyed

  1 ---- 1

+                     // operator + is called
= : 0x22ff2c          // it jums to = operator #### (why ?) ####
copy const : 0x22ff28  // = create a temporary object 
dest :   0x22ff28      // temporary object created by = is destroyed 
dest :   0x22ff2c      // x inside + operator is destroyed

                       // ##################################################
                       // #### HERE #### copy constructor to create a temporory object 
                       // like what happend in = operator and also destructor of this 
                       // temporary object did not called
                       // ##################################################

  2 ---- 2      

+                     // here + operator is called 
const :  0x22ff14     // x is creted 

                      //######################""
                      //#### HERE #### copy constructor ob4 that take ob1+ob2 as an
                      // argument did not get called, why ?
                      // and also + operator did not return a temporary object and then
                      // use it as an argument for the copy constructor
                      //#######################

  3 ---- 3 

dest :  0x22ff14        // x   destroyed
dest :  0x22ff18        // ob3 destroyed
dest :  0x22ff1c        // ob2 destroyed
dest :  0x22ff20        // ob1 destroyed

问题从1到2之间开始,也在2到3之间。

所以我的问题在输出中。
在1和2之间:为什么+运算符没有返回一个teporary对象然后在=运算符中发生销毁?

在2和3之间:为什么+ operato没有返回一个临时对象,它将在复制构造函数中用作参数来创建ob4?

我知道这太长了,但我非常感谢你的帮助。

3 个答案:

答案 0 :(得分:3)

允许编译器删除(删除)复制构造并在适当位置构建(在最终目的地)。所以它完全有效。

PS:小错误:

cat operator=(const cat& rhs){

应该是:

cat &   operator=(const cat& rhs){
// ^^^

通过这次修正,我得到了:

 1----1 

+                       // + called.
const : 0x7fff6b29e848  // Local object to + constructed.
                        // But the return value will be used as a const ref parameter
                        // to the assignment operator. So we can elide the actual copy
                        // if we create the temporary object at the destination and use that.
= :  0x7fff6b29e830     // Now we are in the assignment.
                        // Just copy the value from the temporary object we created as part
                        // of the optimizations.
dest :  0x7fff6b29e848  // All finished destroy the temporary.

                        // Note: I use the term temporary very loosely.
                        //       And refer you to the as-is rule.

答案 1 :(得分:1)

所以你的问题似乎就是这个:

在+方法中,您创建一个名为'x'的本地猫,并将其返回。你期望有一个构造函数调用,然后是一个创建匿名返回值的复制构造函数,然后是x的析构函数,最后是返回值的析构函数。你想知道为什么不发生这种情况。 (如果我错了,请纠正我)

简而言之,答案几乎可以肯定是编译器优化。编译器看到你只是创建x,更改其中一个成员,然后返回它,所以它将完成所有这些并简单地构造返回值。

答案 2 :(得分:0)

编译器已将内部变量x的副本省略为返回值,这是通过将两个对象放在同一内存位置并延长对象的生命周期来完成的。临时的生命周期一直延续到完整表达式结束到您已识别为x的销毁点。我手边没有编译器,但我敢打赌,如果你在x内打印operator+的地址,并且operator=的参数地址将是相同的。< / p>

关于如何实现优化,在所有编译器中,我知道按值返回的函数的调用约定规定调用者保留返回值的空间并将隐藏指针传递给未初始化的内存到函数。函数内的return语句将在该内存块上创建返回的对象。在这种情况下,在处理operator+时,编译器意识到x的整个目的是作为构造返回语句的蓝图并决定放置 {{1在地址中传递返回的值,并避免必须创建两个单独的对象并进行复制。

进一步阅读:Value semantics: NRVO // Value Semantics: copy elision

编辑:运营商+

中NRVO的等效代码转换

调用约定使x等同于:

operator+

现在编译器发现它可以轻松执行NRVO并进一步将其转换为:

void operator+( void* rtn, cat * const this, cat const &rhs ) {
   cout << "+" << endl;
   cat x;
   x.a=this->a+rhs.a;
   new (rtn) cat(x);    // return x;
}