浅拷贝和深拷贝
浅拷贝
只对对象中的数据成员进行简单的赋值(值拷贝);默认拷贝构造函数是浅拷贝;
深拷贝
对于对象中动态成员,重新动态分配空间,再把内容复制到新的内存空间;
拷贝构造函数
参数是一个左值引用。系统自定义的拷贝构造函数是浅拷贝,自定义拷贝构造一般为深拷贝;使用默认拷贝构造函数时,如果类对象中有指针成员,会因为新对象的指针指向的地址与被拷贝对象的指针指向的地址相同,造成指针被delete两次的错误;深拷贝会重新开辟一块内存空间,为了避免拷贝开销,引入移动构造函数。
类的对象需要拷贝时,拷贝构造函数将会被调用。会调用拷贝构造函数的情况:
- 一个对象以值传递的方式传入函数体 ;
- 一个对象以值传递的方式从函数返回 ;
- 一个对象需要通过另外一个对象进行初始化。
移动语义
以移动而非深拷贝的方式初始化含有指针成员的类对象;也就是将其它之后不需要的对象拥有的内存移为己用。
移动构造函数
参数是一个右值引用。移动构造函数首先将传递参数的内存地址空间接管,源对象的数据成员分配给默认值(指针设置为nullptr),并且在原地址上进行新对象的构造,最后调用原对象的的析构函数,这样做既不会产生额外的拷贝开销,也不会给新对象分配内存空间。
当类中同时包含拷贝构造函数和移动构造函数时,如果使用临时对象初始化当前类的对象,编译器会优先调用移动构造函数来完成此操作。只有当类中没有合适的移动构造函数时,编译器才会退而求其次,调用拷贝构造函数。
默认情况下,左值初始化同类对象只能通过拷贝构造函数完成,如果想调用移动构造函数,则必须使用右值进行初始化。C++11 标准中为了满足用户使用左值初始化同类对象时也通过移动构造函数完成的需求,新引入了 std::move() 函数,它可以将左值强制转换成对应的右值。
std::move() 函数
将一个左值强制转化为右值引用,以用于移动语义。将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝。通过std::move(),可以避免不必要的拷贝操作。