移动构造函数

时间:2021-08-09 19:26:38

   C++03 性能上被长期被诟病的其中之一,就是其耗时且不必要的深度拷贝。深度拷贝会发生在当对象是以传值的方式传递。举例而言,std::vector<T> 是内部保存了C-style 数组的一个包装,如果一个std::vector<T>的临时对象被建构或是从函数返回,要将其存储只能通过生成新的std::vector<T>并且把该临时对象所有的数据复制进去。该临时对象和其拥有的内存会被摧毁。

  而有了右值引用后,就可以直接使用右值引用的指针值,无需再重新分配内存和拷贝了。

  这里,举一个赋值构造函数和移动构造函数的例子。Person类有三个构造函数,定义如下。

class Person {
public:
Person(
int p) {
num
= new int;
*num = p;
};
Person(Person
& rhs) ;//赋值构造函数
Person(Person&& rhs) ;//移动构造函数
~Person() {
if (num) {
delete num;
}
};
private:
int *num = NULL;
};

   赋值构造函数,使用深度拷贝进行赋值。

Person::Person(Person& rhs) {
cout
<< "copy constructor" << endl;
if (num) {
delete num;
}
num
= new int;
*num = *rhs.num;
}

  右值引用定义为T&&,这样我们可以把右值的内存直接拿过来而不需要重新申请内存。在将右值引用rhs的指针num赋值给当前实例后,需要将右值引用的指针num赋值为nullptr,这样离开当前作用域后右值引用的num指针就不会被释放。这样就有效的减少了深度拷贝导致的内存与效率浪费。

Person::Person(Person&& rhs) {
cout
<< "move copy constructor" << endl;
if (this != &rhs) {
if (num) {
delete num;
}
num
= rhs.num;
rhs.num
= nullptr;//这样rhs析构的时候不会释放num
}
}

   实际应用如下,Person(4)作为一个右值引用初始化p3,有效的减少了深度拷贝造成的资源浪费。

void testPerson() {
Person p1(
3);
Person p2(p1);
Person p3(Person(4));
Sleep(
0);
}