我有以下代码:
#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 =返回值)。
答案 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=
的输入,因为它是一个临时的,因此无论如何都会在之后被销毁。