拷贝控制成员
拷贝、赋值和销毁
- 拷贝初始化不仅在用=定义变量时会发生,将一个对象作为实参传递给一个非引用类型的形参、从一个返回类型为非引用类型的函数返回一个对象、用花括号列表初始化一个数组中的元素或一个聚合类中的成员也会执行拷贝初始化。
- 在一个析构函数中,首先执行函数体,然后销毁成员。成员按初始化顺序的逆序销毁。
- 内置类型没有析构函数,因此销毁内置类型成员什么也不需要做。
- 无论何时一个对象被销毁,就会自动调用其析构函数:变量在离开作用域时被销毁;当一个对象被销毁时,其成员被销毁;容器(包括数组)被销毁时,其元素被销毁;对于动态分配的对象,当对指向它的指针应用delete运算符时被销毁。
- 当指向一个对象的引用或指针离开作用域时,析构函数不会执行。
- 只能对具有合成版本的成员函数使用=default。
- =delete必须出现在函数第一次声明的时候,可以对任何函数指定delete。
- 如果一个类有数据成员不能默认构造、拷贝、赋值或销毁,则对应的成员函数将被定义为删除的。
- 通常管理类外资源的类必须定义拷贝控制成员。
- 赋值运算符一般满足:将一个对象赋予它自身,赋值运算符必须能正确工作;大多数赋值运算符组合了析构函数和拷贝构造函数的工作。
- 一般而言,一个左值表达式表示的是一个对象的身份,而一个右值表达式表示的是对象的值。
- 右值引用指向将要被销毁的对象。因此我们可以从绑定到右值引用的对象“窃取”状态。
- 除了保证移后源对象可析构,还需要保证移后源对象是有效的,但是用户不能对其值进行任何假设。
- 与拷贝操作不同,编译器不会为某些类合成移动操作。只有当一个类没有定义任何自己版本的拷贝控制成员,且类的每个非static数据成员都可以移动时,编译器才会为它合成移动构造函数或移动赋值运算符。
- 定义了一个移动构造函数或移动赋值运算符的类必须也定义自己的拷贝操作。否则,这些成员默认地被定义为删除的。移动操作和合成的拷贝控制成员间有个相互作用的关系。
- 移动迭代器的解引用运算符生成一个右值引用
术语
- 合成拷贝构造函数
- 参数和返回值
- 拷贝初始化的限制
- 编译器可以绕过拷贝构造函数
- 重载赋值运算符
- 合成的拷贝赋值运算符
- 析构函数完成的工作
- 合成析构函数
- 需要析构函数的类也需要拷贝和赋值操作
- 需要拷贝操作的类也需要赋值操作,反之亦然
- 定义删除的函数
- 析构函数不能是删除的成员
- 合成的拷贝控制成员可能是删除的
- 左值持久;右值短暂
- 变量是左值
- 标准库move函数
- 移动操作、标准库容器和异常
- 移动赋值运算符
- 移后源对象必须可析构
- 合成的移动操作
- 移动右值,拷贝左值
- 但如果没有移动构造函数,右值也被拷贝
- 拷贝并交换赋值运算符和移动操作
- 建议:不要随便使用移动操作