繁体   English   中英

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

[英]c++ overloaded + operator does not return a temporary object , why?

这是源代码:

#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之间:为什么+运算符没有返回过渡对象,然后销毁=运算符中发生的事情?

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

我知道这已经很长时间了,但是我非常感谢您的帮助。

允许编译器删除(删除)副本构造并就位构建(在最终目标位置)。 因此,这是完全有效的。

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.

所以你的问题似乎是这样的:

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

简而言之,答案几乎肯定是编译器优化。 编译器看到您只是在创建x,更改其成员之一,然后返回它,因此它将所有内容取出并仅将返回值构造就位。

编译器已将内部变量x的副本复制到返回的值中,这是通过将两个对象都放在相同的内存位置并延长对象的生存期来完成的。 临时项的生存期一直延长到整个表达式的结尾,直到您将其标识为x的销毁为止。 我没有手头的编译器,但我敢打赌,如果您在operator+内打印x的地址和operator=的参数地址,它们将是相同的。

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

进一步阅读: 值语义:NRVO // 值语义:复制省略

编辑 :运算符+中的NRVO的等效代码转换

调用约定使operator+等效于:

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;
} 

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

void operator+( void* rtn, cat * const this, cat const &rhs ) {
   cout << "+" << endl;
   new (rtn) cat;                                 // cat x;
   *static_cast<cat*>(rtn).a = this->a+rhs.a;     // `x` is an alias to 
   // return x; unnecessary, the return object has been built in place already
} 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM