由于c++11中对左值和右值进行了区分。因此big three变成了五个基本原则
新增的第一部分——重载拷贝构造函数
观察下面的代码:
上面代码中:
- a是左值,因为我们能取到a的地址;
- b是左值,因为b是有并且的类型的。
- c是b的引用,可以取到地址,因此c也是一个左值
- move是一个辅助函数,他告诉编译器,想办法把函数括号中的东西转成右值。右值拥有的一切特征,左值都拥有,因此可以把左值转换成一个右值。
- 因此上图中d是一个右值。
C++11中对拷贝构造函数进行重载——传入一个右值作为拷贝构造函数的参数
对于右值来说,很多情况下都是临时变量。该重载希望将传入的右值所占用的资源完全的移交到左边。
class RuleOfFive {
public:
RuleOfFive(const RuleOfFive& rhs):m_value(new int(*(rhs.m_value))){}
//重载拷贝构造函数
RuleOfFive(RuleOfFive&& rhs);
private:
int *m_value;
};
RuleOfFive::RuleOfFive(RuleOfFive&& rhs) {
m_value = rhs.m_value;
rhs.m_value = nullptr;
}
判断重载的拷贝构造函数是否调用成功的依据就是传入的参数rhs.m_value是否变成了指向nullptr的指针(判断指针是否为nullptr也是保证了该块内存不被重复析构的原因,侯捷老师的C++11的课里面有讲,之后整理完笔记我再在此处补充讲解链接)。
调用方法:
int main(){
RuleOfFive b;
//常规调用拷贝构造函数的方法
RuleOfFive e=b;
//调用重载后的拷贝构造函数的方法
//执行完这句之后,b的值尽量不要再去使用,因为被修改了
RuleOfFive d=move(b);
}
新增的第二部分——重载拷贝赋值函数
class RuleOfFive {
public:
//...
RuleOfFive& operator=(const RuleOfFive& rhs) {
*m_value = *(rhs.m_value);
return *this;
}
//重载拷贝赋值函数
RuleOfFive& operator=(RuleOfFive&& rhs) {
if (&rhs == this) return *this;
//直接释放m_value是错误的,如果调用者使用自己来对自己进行拷贝赋值,就会出错
delete m_value;
//直接赋值会造成m_value之前指向的内存发生泄漏,因此赋值前需要将m_value所指的那块内存释放
m_value = rhs.m_value;
rhs.m_value = nullptr;
return *this;
}
private:
int *m_value;
};
调用方法:
int main(){
RuleOfFive b;
RuleOfFive e;
//调用重载之后的拷贝赋值函数
e=move(b);
}