当我们决定一个类是否要定义它自己版本的拷贝控制成员时,可以看这个类是否需要需要一个析构函数.
拷贝构造函数:构造函数第一个参数必须是自身类类型的引用.(否则参数会产生新的构造函数,循环下去)
string s("abc");//直接初始化,使用普通的函数匹配
string s2 = "abc";//拷贝初始化,将右侧对象拷贝到正在创建的对象中,如果需要的话还要进行类型转换.拷贝初始化依靠拷贝构造函数或移动构造函数来完成
//拷贝初始化还在下列情况下发生
//对象的非引用类型参数传递
//函数返回一个非引用类型的对象
//某些类型会对他们分配的对象使用拷贝初始化
//emplacement创建的元素都是进行直接初始化
//
拷贝赋值运算符:重载赋值运算符,非构造时期执行的拷贝操作.
析构函数:首先执行函数体,然后销毁成员.按成员初始化顺序逆序销毁.
需要析构函数的类必然也需要拷贝和赋值操作.一个类需要拷贝构造函数,几乎可以肯定也需要一个拷贝赋值运算符,反之亦然
=default 显示要求编译器生成合成的版本.
=delete定义为删除的函数,与default不同,可以对任意函数指定delete
如果一个类型删除了析构函数,那么编译器不允许直接定义这种类型的变量,但是可以动态分配这种类型的对象,但不能释放.
赋值运算符通常组合了析构函数和构造函数的操作,而且要保证一个对象赋值与他本身是正确的
对于分配了资源的类,定义swap是一种重要的优化手段
在赋值运算中使用拷贝并交换,按值传递到参数,形成安全临时变量,交换之后,得到赋值,临时变量消失时,原变量得以析构.
移动构造函数,类似拷贝构造函数,第一个参数是该类类型的一个右值引用.移动构造函数需要确保移动后源对象处于一种状态:销毁它是无害的.
当使用一个右值进行初始化或者赋值时,此右值即将销毁无用,但是内部的资源可安全的传递给被初始化或赋值对象,那么定义移动构造函数可以优化.许多标准库中使用移动构造函数,(要求标记为noexception,测试没有标记noexception也使用了移动构造函数.)
注意:不能再使用右侧运算对象的资源之前就释放左侧运算对象的资源(可能是相同的资源)
除了将移动后源对象置为析构安全的状态外,移动操作还必须保证对象仍然是有效的,即可以安全的为其赋予新值或可以安全的使用而不依赖其当前值.
引用限定符