SpartacusIn21

专注:c++,python,d3d,设计模式,人工智能,并行计算

移动构造函数

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

 

posted on 2017-11-15 18:04  SpartacusIn21  阅读(365)  评论(0编辑  收藏  举报

导航