拷贝构造和移动构造对比
拷贝构造
代码1:
#include <iostream>
using namespace std;
class HasPtrMem {
public:
HasPtrMem() : d(new int(0)) {
cout << "Construct: " << ++n_cstr << endl;
}
HasPtrMem(const HasPtrMem &rhs) : d(new int(*rhs.d)) {
cout << "Copy Construct: " << ++n_cpstr << endl;
}
~HasPtrMem() {
delete d;
d = nullptr;
cout << "Destruct: " << ++n_dstr << endl;
}
int *d;
static int n_cstr;
static int n_dstr;
static int n_cpstr;
};
int HasPtrMem::n_cstr = 0;
int HasPtrMem::n_dstr = 0;
int HasPtrMem::n_cpstr = 0;
HasPtrMem getTemp()
{
return HasPtrMem();
}
int main()
{
HasPtrMem a = getTemp();
return 0;
}
这个程序应该输出:
Construct: 1 // getTemp函数中的HasPtrMem()表达式显示调用构造函数,生成临时变量temp
Copy Construct: 1 // 从临时变量temp拷贝构造出一个临时值来作为getTemp函数的返回值
Destruct: 1 // temp析构
Copy Construct: 2 // main中从getTemp函数的返回值拷贝构造出a
Destruct: 2 // getTemp函数的返回值析构
Destruct: 3 // a析构
进行了两次拷贝构造。如果HasPtrMem的指针指向非常大的堆内存数据的话,那么拷贝构造的过程就会非常昂贵。
而实际在VS2013环境下输出:
Construct: 1
Destruct: 1
这是因为编译器对函数返回值作了优化,即RVO(Return Value Optimization)。
移动构造
移动构造:在构造时使得临时对象的堆内存资源直接“移动”到对象a下,同时保证临时对象不释放其所指向的堆内存。这样在构造完成后,临时对象被析构,a就得到了临时对象所拥有的堆内存资源。
代码2:
#include <i