拷贝控制操作即对象的拷贝,移动,赋值和销毁。一个类通过拷贝构造函数,拷贝赋值运算符,移动构造函数,移动赋值运算符和析构函数来完成这些工作。拷贝和移动构造函数定义了当用相同类型的另一个对象初始化本对象时做什么。拷贝和移动运算符定义了将一个对象赋予同类型的另一个对象时做什么。析构函数定义了当此类型对象销毁时做什么。
如果一个类没有定义这些拷贝控制成员,编译器会自动为它定义缺失的操作。不过,对于一些特殊的类来说,这会引起很大的麻烦
拷贝、赋值与销毁:
拷贝构造函数:
如果一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都有默认值,则此构造函数是拷贝构造函
拷贝构造函数的第一个参数几乎总是一个 const 的引用。因为拷贝构造函需要数被用来初始化非引用类类型参数。如果其参数不是引用类型,则永远不会成功——为了调用拷贝构造函数,我们必须拷贝它的实参,但为了拷贝实参,我们又需要调用拷贝构造函数,如此无限循环。
拷贝构造函数在有些情况下会被隐式的使用,因此拷贝构造函数通常不应该是 explicit 的
与合成默认构造函数不同,即使我们定义了其它构造函数(没有定义拷贝构造函数),编译器也会为我们合成一个拷贝构造函数
对于某些类来说,合成拷贝构造函数用来阻止我们拷贝该类类型的对象。对于这些特殊的类(如IO类等),编译器会默认合成拷贝构造函数并将其定义为 delete 的成员
而一般情况,合成的拷贝构造函数会将其参数逐个拷贝到我们正在创建的对象中。编译器从给定的对象中将每个非 static 成员拷贝到正在创建的对象中。
每个成员的类型决定了它如何拷贝:对类类型的成员,会使用拷贝构造函数来拷贝;内置类型的成员则直接拷贝。虽然我们不能直接拷贝一个数组,但合成拷贝构造函数会逐元素地拷贝一个数组的成员。如果数组元素是类类型,则使用元素的拷贝构造函数来进行拷贝。
拷贝初始化:
1 #include <iostream> 2 using namespace std; 3 4 int main(void){ 5 string a(10, 'a');//直接初始化 6 string b(a);//直接初始化 7 string c = a;//拷贝初始化 8 string d = "fk";//拷贝初始化 9 string e = string("fl");//拷贝初始化 10 11 return 0; 12 }