复制构造函数没有调用,为什么?

时间:2012-06-29 13:06:34

标签: c++

  

可能重复:
  Why copy constructor is not called in this case?

我有以下代码:

#include <iostream>
#include <new>

using namespace std;

class test {  
    int *p;  
public:
    test operator=(test a);
    test()  {
        p = new int [2];
        cout <<"Default Constructor was done here." << "\n";
    }

    test(const test &a) {
        p = new int [2];
        this->p[0] = a.p[0];
        this->p[1] = a.p[1];
        cout << "Copy Constructor was done here." << "\n";
    }

    ~test() {
        delete p;
        cout << "Destructor was done here." << "\n";
    }
    int set (int a, int b) {
        p[0] = a;
        p[1] = b;
        return 1;
    }

    int show () {
        cout << p[0] << " " << p[1] << "\n";
        return 2;
    }
};    

test test::operator=(test a) {
    p[0] = a.p[0]; 
    p[1] = a.p[1]; 
    cout << "Operator = was done here" << "\n";
    return *this;
}

test f(test x) {
    x.set(100, 100);
    return x;
}

int main () {
    test first;
    test second;
    first.set(12, 12);

    //f(first);
    //second = first;
    second = f(first);


    first.show();
    second.show();

    getchar ();
    return 0;
}

复制构造函数只被调用了三次?为什么? 如果我理解,我们制作了四个副本(我们将对象发送到func,func返回值,我们将对象发送到operator =,operator =返回值)。

1 个答案:

答案 0 :(得分:3)

这可能是copy elision的影响。编译器可以自由地避免在不对程序产生影响的任何地方复制对象。复制构造函数/析构函数的副作用不被视为对此案例中程序的影响。一般来说,它会避免复制临时用作函数参数,因为无论如何临时都会被销毁。

这可以在标准中的§12.8.32中找到:

  

当满足某些条件时,允许省略实现   复制/移动类对象的构造,即使复制/移动   对象的构造函数和/或析构函数具有副作用。在这样的   在这种情况下,实现处理省略的源和目标   复制/移动操作只是两种不同的方式来指代   同一个对象,该对象的破坏发生在后期   两个物体在没有物体的情况下被摧毁的时间   优化。这种复制/移动的省略   以下允许称为copyelision的操作   情况(可能合并以消除多个副本):

     
      
  • 在具有类返回类型的函数的return语句中,当表达式是具有
    非易失性自动对象的名称时   与函数返回类型相同的cv-unquali fi ed类型   通过构造自动
    来省略复制/移动操作   直接将对象转换为函数的返回值
  •   
  • 在throw-expression中,当操作数是非范围自动对象的名称时,其范围不会超出范围   最里面的封闭try-block(如果有的话)的结尾,   从操作数复制/移动操作到异常对象(15.1)   可以通过直接构造自动对象来省略   异常对象
  •   
  • 当一个未绑定到引用(12.2)的临时类对象被复制/移动到一个类对象时   相同的cv-unquali fi ed类型,复制/移动操作可以省略   将临时对象直接构造到目标中   省略了复制/移动
  •   
  • 当异常处理程序的异常声明(第15条)声明一个相同类型的对象(cv-quali fi cation除外)作为
      异常对象(15.1),可以省略复制/移动操作   将异常声明作为例外的别名进行处理   对象,如果程序的含义将保持不变,除了   执行由
    声明的对象的构造函数和析构函数   例外声明。
  •   

在这种情况下,它可能只是使用f返回的对象作为operator=的输入,因为它是一个临时的,因此无论如何都会在之后被销毁。