cpp primer 第十三章笔记
嘿嘿,飙到第十三章了~~老司机的笑容像天上的弦月~~毕竟是补漏。。。
- 拷贝构造函数通常不应该是explicit的,参数必须为引用类型(常量引用)
- 合成的拷贝构造函数对于数组成员会逐一拷贝其元素
- 编译器有时会绕过拷贝构造函数(优化为直接构造)
- 三/五法则:析构函数,拷贝构造函数,拷贝赋值运算符,移动构造函数,移动赋值运算符,可以看成一个整体,通常需要定义其中一个也就意味着需要定义其余四个。
- 新司机还记得
=default不? - 阻止拷贝:旧标准可以把相关构造函数声明为private,不需要定义;新标准可以用
=delete。当不能拷贝、赋值或销毁类的成员时,类的合成拷贝控制成员就被定义为删除的 - 对于一个赋值运算符,编写时需要考虑:
- 一个对象赋值给它自身,要工作正常(所以要在析构当前对象前保存“新”对象)
- 拷贝+析构
如果swap操作不会拷贝对象而只是交换指针(通常都是如此),那么可以利用“拷贝并交换”技术来编写赋值运算:
tc& operator=(tc rhs){ //传值复制了rhs swap(*this,rhs); return *this; } //rhs也就是原来的本对象会自动析构左值引用不能绑定到要求转换的表达式、字面常量、返回右值的表达式,但是常量左值引用可以哦,而右值引用则和左值引用完成相反
int i=10; double &rd=i; //error int &ri=30; //error int &rri=i+3; //error右值短暂,都是临时对象,左值持久。
右值和右值引用是不一样的,简单的说,右值就是临时量,不是变量,而右值引用是引用右值的变量,是个变量,它通过引用右值(临时量)将临时量变为变量,本来临时量马上就会消亡,你一用右值引用引用它,就把它变成一个持久的变量了,所以primer说,右值引用从绑定到其的临时量中“窃取”状态。同样的,右值引用是一个变量不是临时量,所以右值引用不能绑定右值引用(绕口。。。),还有,右值意味着它只有你这个所有者,你可以为所欲为(修改它)
使用
std::move可以将一个左值转换为右值引用,也就是告诉编译器,这个左值劳资要当成右值用,你放心,过会儿劳资就削了它!(也就是说除了销魂不能对它再做任何操作,起始还可以再赋值给他,但是不能直接使用它的值。。。) 1. 移动构造函数和移动赋值运算符,参数都是非const的右值引用,调用后移后对象应处于可析构状态(意思是说,假设把a移动给b,就算你在调用移动构造函数之后把a析构了,也不会影响到b的内容,主要是考虑指针的处理),再者二者不应该抛出异常,使用noexcept关键字(编译器看到这个关键字的话,在这个函数抛出异常时,会直接调用terminate(),同时,它也告诉标准库容器该类的移动构造函数不会抛出异常,否则,标准库会因为预防发生异常的时候需要恢复原状而使用拷贝语义)。拷贝左值,移动右值,没有移动就只能拷贝右值
标准库的重载函数往往有两个版本:
void push_back(const X&); //copy void push_back(X&&); //move拷贝操作对参数应该没有影响,故而必然是const的,而移动操作会对移后对象进行操作,所以必然是非const的
可以在成员函数后面活着重载运算符后面加引用限定符表示this指向的对象只能是左值或者右值
class foo{ public: foo& operator=(const foo&) &; //只有左值才能使用= void somefunc() &&; //只有右值才能使用该函数 void hehe() const &; //只有const左值才能使用该函数,const必须在前 }至于重载函数,const限定符的成员函数和同名同参的普通成员函数构成重载,而不同引用限定符的同名同参成员函数之间也构成重载,重载的对象就是类本身是左值还是右值。另外,一旦在const限定符与普通重载函数之间的任何一个上用了引用限定符,那这一组重载函数中就都得用引用限定符了;
