好久不见,回来更新了。这一章介绍了对类的拷贝控制的操作,其中最重要的是13.1对类的五大基本操作函数的理解和13.6对右值引用和对象移动的理解,比较长需要慢慢看。
这章的13.1是面向对象编程非常重要的一部分,而13.6的右值引用则几乎是C11最重要的新特性,值得重点理解。从这开始是第三部分"类设计者的工具"了,都是C++最区别于C的地方。
13.1 拷贝,赋值与销毁
FOO(const FOO& inp) {
// 拷贝构造的通常形式, 由于是拷贝所以一般不修改源值
// 而且使用const也提高了接受的参数范围
// 参数必须是自身引用防止了自赋值问题的产生
}
FOO& operator=(const FOO& inp) {
// 拷贝赋值运算符常见形式
// 接受一个右侧类型引用,返回左侧类型引用
}
~FOO() {
// 析构函数,无参无返回值
}
//指定此函数为合成版本的,由编译器生成函数体
FOO(const FOO& inp) = default;
13.2 拷贝控制和资源管理
13.3 交换操作
FOO& operator=(FOO inp) {
// 这个写法保证了自赋值的正确和异常安全
// 由于赋值是通过与一个副本进行交换值然后再销毁副本
// 所以自赋值能正常进行
// 由于这部分中可能发生异常的地方在赋值前构造副本的地方
// 因此是异常安全的,发生异常也不会影响原值
swap(*this, inp);
return *this;
}
13.6 对象移动
// 变量属于左值,最显眼的特性是变量可以取地址
int test = 1;
// 左值引用可以得到变量的引用
int& t_left = test;
// 但是对于1这种临时值,无法进行左值引用,但此时可以进行右值引用
int&& t_right = 1;
// 但我们可以将const左值引用绑定到右值上
const int& t_cleft = 1;
FOO(FOO&& inp) noexcept
:p(inp.p) {
// 移动构造的一般形式
// 先声明不会抛出异常
// 然后在初始化部分中复制传入的右值引用的指针
// 右值引用的操作类似于一个普通的对象
inp.p = nullptr;
// 再将传入的对象的指针赋值为nullptr保证可以无害析构
// 最后在函数外将传入的对象销毁完成控制权转移
}
// 从上到下依次是:
// 普通函数,左值限定函数,右值限定函数,左值限定函数常量版本,右值限定函数常量版本
FOO test_normal();
FOO test_left()&;
FOO test_right()&&;
FOO test_left()const&;
FOO test_right()const&&;