构造函数:用同类型的另一个对象初始化本对象时做什么。
赋值运算符:将一个对象赋予同类型的另一个对象时做什么。
拷贝构造函数:若一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都有默认值。
拷贝构造函数在几中情况下都会被隐式地使用,所以拷贝构造函数不应该是explicit。
如果没有为一个类定义拷贝构造函数,编译器会定义一个,即使定义了其他构造函数,编译器也会合成一个拷贝构造函数。
一般情况下,合成的拷贝构造函数会将其参数的成员逐个拷贝到正在创建的对象中,但对某些类,合成拷贝构造函数用来阻止拷贝该类类型的对象。
成员类型决定拷贝方式:1.类类型的成员,使用拷贝构造函数。 2.内置类型,直接拷贝
数组虽然不能够直接拷贝,但合成拷贝构造函数会逐元素地拷贝一个数组类型的成员。
使用拷贝初始化:1.用“=”定义变量时发生 2.将一个对象作为实参传递给一个非引用类型的形参 3.从一个返回类型为非引用类型的函数返回一个对象 4.列表初始化。
初始化标准库容器,用emplace成员创建的元素都进行直接初始化,因为拷贝构造函数被用来初始化非引用类型参数,所以拷贝构造函数的参数必须是引用类型。
拷贝初始化过程中,编译器可以跳过拷贝/移动构造函数,直接创建对象,但即使如此,拷贝/移动构造函数必须是存在且可访问的。
为了与内置类型的赋值保持一致,赋值运算符通常返回一个指向其左侧运算对象的引用,如果一个类未定义自己的拷贝赋值运算符,编译器会生成一个合成拷贝赋值运算符,将右侧运算对象的每一个非static成员赋予左侧运算对象的对应成员。
析构函数释放对象使用的资源,并销毁对象的非static数据成员。析构函数是类的一个成员函数,名字由波浪号接类名构成,没有返回值,也不接受参数,所以析构函数不能够被重载。对于一个给定类,只会有唯一一个析构函数。
析构函数中,首先执行函数体,然后销毁成员,成员按初始化顺序的逆序销毁。
销毁类类型的成员需要执行成员自己的析构函数,内置类型没有析构函数,销毁内置类型成员什么也不需要做。
析构函数调用:1。变量在离开其作用域时被销毁 2.当一个对象被销毁时,其成员被销毁 3.容器被销毁时,其元素被销毁 4.对于动态分配的对象,当对指向它的指针应用delete运算符 5.对于临时对象,当创建它的完整表达式结束时被销毁
当指向一个对象的引用或指针离开作用域时,析构函数不会执行。
析构函数体自身并不直接销毁成员,成员是在析构函数体之后隐含的析构阶段中被销毁的。需要析构函数的类也需要拷贝和赋值操作。
合成析构函数不会delete一个指针数据成员。
可以通过将拷贝控制成员定义为“=default”来显示地要求编译器生成合成的版本。
对某些类来说,定义类时必须采用某种机制阻止拷贝或赋值,例如:iostream类阻止了拷贝,以避免多个对象写入或读取相同的IO缓冲。
C++11下,可通过将拷贝构造函数和拷贝赋值运算符定义为“删除的函数”来阻止拷贝。(在参数列表后加上“=delete”)
“=delete”通知编译器,不希望定义这些成员。
可以对任何函数指定“=delete”,但只能对编译器可以合成的默认构造函数或拷贝控制成员使用“=default”。
析构函数不能是“=delete”,会无法销毁类的对象。
本质上,当不可能拷贝、赋值或销毁类的成员时,类的合成拷贝控制成员就被定义为“=delete”。
管理类外资源的类必须定义拷贝控制成员,为了定义这些拷贝控制成员,首先必须确定此类型对象的拷贝语义:定义拷贝操作,使类的行为看起来像一个值或指针。
编写一个赋值运算符,先将右侧运算对象拷贝到一个局部临时对象中,当拷贝完成后,销毁左侧运算对象的现有成员就是安全的了,一旦左侧运算对象的资源被销毁,只剩下将数据从临时对象拷贝到左侧运算对象的成员中。