C++primer阅读笔记----------拷贝控制

该博客用于记录自己在阅读过程中不懂的知识点,很少用到但比较重要的知识点以及模棱两可的知识点


为了很好的操作类,我们通过定义5种特殊的成员函数来完成(拷贝控制操作):

拷贝构造函数
拷贝赋值运算符
移动构造函数
移动构造运算符
析构函数
拷贝构造函数第一个参数必须是一个引用类型(且几乎都是const),且额外的参数必须有默认值
拷贝构造函数在多种情况下都会被隐式的引用,所以不应该是explicit

花括号列表初始化也属于拷贝初始化,标准库容器中的insert和push也是拷贝初始话,而emplace则是直接初始化

拷贝构造函数用来初始化非引用类类型的参数,同时这解释类为什么拷贝构造函数的形参类型为什么是引用:如果不是引用的话,调用拷贝构造函数时在拷贝构造函数内部,我们需要使用拷贝构造函数的形参,而用实参初始化形参时又会调用拷贝构造函数,如此就会无穷无尽

explicit(抑制隐式转换)形式的构造函数只能直接初始化

标准库通常要求保存在容器中的类型要具有赋值运算符,赋值运算符返回一个指向其左侧运算对象的引用

对于某些类,合成拷贝赋值运算符通常是为了禁止该类型对象赋值

析构函数中,首先执行函数体,然后销毁成员(函数体之后隐含的析构阶段),按初始化顺序的逆序(总之就算和构造函数相反)

要注意是一点是隐式的销毁一个内置指针不会delete它所指对象(智能指针的好处, 智能指针是类类型)

如果一个类需要自定义一个析构函数,那么几乎可以肯定它也需要一个拷贝构造函数(初始化)和拷贝赋值运算符(赋值),因为如果使用自动合成的的话,可能会导致多个内置指针指向同一块动态申请的内存,进而导致析构时多次delete,这显然是错的
有时候两个对象之间的拷贝或者赋值情况并不合法时(如,我们不希望多个对象写入或读取相同的IO),或许你会觉得不定义拷贝构造函数和拷贝赋值运算符就行了,但是这样是错的,编译器将会自动合成,所以此时我们可以定义删除函数来解决(与default相似)
NoCopy() = default;
NoCopy(const NoCopy &) = delete;
NoCopy &operator = (const NoCopy &) = delete;

如果一个类有数据成员不能默认构造,拷贝,复制或销毁,则对应的成员函数将被定义为删除的

我们定义拷贝构造函数和拷贝赋值运算符时,应该明确此类型的拷贝语义,值(副本和原对象是两个独立的个体)或指针(虽然是两个指针,但共享所指对象)

(值)拷贝赋值运算符中,如果类类型中有指针数据成员,应先将右侧对象所指数据存到一个临时变量,再销毁现有指针所指对象,再进行拷贝,如果不创建临时变量直接销毁拷贝的话,如果左右值当前指针数据成员所指对象是同一个,那先销毁的话,拷贝就无法继续了

(指针)拷贝赋值运算符中应先递增右侧运算符的计数器,再递减左侧,这样的话就可以避免两个对象的计数器是同一个(即指向同一个对象),先减后加的话,如果恰好计数器为0把对象销毁了的话,程序就不能继续下去了

对于分配类资源的类,我们定义swap(交换指针,避免为临时对象分配资源)是一种有效的优化手段,如果存在特定版本的swap,其匹配程度会优先于std版本,作用域中要有std的using声明(特定版本的会隐藏std版本的)

定义了swap操作的类,通常一种拷贝并交换的技术来定义赋值运算符,将左侧运算对象和右侧运算对象的一个拷贝交换
myclass& operator=(myclass a){
swap(*this, a);
return *this;
}

深拷贝:即上述的拷贝语义为值
浅拷贝:即上述所说的语义为指针

某些情况如,对象拷贝后原对象就销毁了,移动而非拷贝会大幅提高性能

通常不给move提供using声明,意味着我们应该使用std::move()而不是move(挖坑)

当使用move从旧容器中接管元素的所有权之后,旧容器中还有什么东西呢,我们不考虑这一点,我们只需要知道,执行它的析构函数是安全的

返回左值引用的函数,连同下标, 赋值,解引用, 前置递增减,左值是一种对象身份,所以可以有持久的状态
返回右值引用的函数,连同算术,关系,位,后置递增减, 右值实际上注重的是值,它通常可以是字面值常量,或者临时对象,该对象没有其他用户,即将被销毁

使用move将左值转换成右值,注意使用std::move

使用noexpect表示该函数不抛出异常
为什么要让函数不抛出异常呢,假设移动一个vector,移动的同时会销毁源元素,如果中途抛出了异常,导致并为完全移动成功,但是源元素却部分销毁。因此,除非我们知道移动构造函数不会抛出异常,否则使用拷贝构造函数会更安全

移动构造函数和移动赋值运算符,都要将目标元素置为可析构状态,并且考虑自赋值问题

当类没有任何自己版本的拷贝控制成员,且它们的所有数据成员都能移动构造或移动赋值,编译器才会为它合成移动构造函数或移动赋值运算符

如果没有移动构造函数,但有拷贝构造函数,初始化如果实参是右值也将调用拷贝构造函数

移动迭代器(确信移动后不再访问,再使用)

引用限定符& 和&&(加在参数列表后)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值