条例11
在operator=中处理自我赋值
- 重载赋值操作符的时候要记得考虑自我赋值的情况,虽然没有意义但语法是合法的。
- 假如你的赋值操作先把被赋值对象删除(防止原先的值内存泄漏)再重新对其进行赋值的话,若这时候不特殊处理,在自我赋值的时候就会出现野指针问题。可以通过正通测试(判断地址是否相同)来处理
- 若我们注意异常安全性就可以直接避免这些问题。例如我们提前保存下来要删除的指针,在修改后再删除就能天然避免这些问题。
- 若想提高效率可以采用现代写法。在赋值操作内创建一个新的要拷贝的值(调用拷贝构造),在通过swap交换当前值和新构造的值,这样新创建的对象在生命周期结束时会自动析构当前值。
- 若想进一步优化,可以在传参的时候不使用引用传参,这样就不用调用拷贝构造创建新的变量,可以直接交换传进来的值。这样能充分利用传参时形成的拷贝构造。
总结
- 应当确保赋值操作有良好的行为。
- 确保自己赋值时行为仍然正确。
条例12
复制对象时不能忘记其每个成分
- 若你自己创建了一个类,并实现了拷贝构造和拷贝赋值。若此时你在类内新增加了一个成员变量,且忘记更改拷贝构造的时候,这时候拷贝构造执行的就是局部拷贝,由于你自己生成了拷贝函数,编译器不会生成拷贝函数也不会检查你的拷贝函数是否完全。
- 这个问题在继承里也会出现。有可能出现子类成员被拷贝了,但父类成员没被拷贝的情况。这时就要主动调用父类成员的拷贝函数。
- 用拷贝构造复用拷贝赋值是没有意义的。拷贝构造是用来初始化新对象的。赋值是在已经创建的对象上赋值。对没被构造的函数赋值没有意义。
总结
- 拷贝函数应该保证赋值对象内所有成员变量,以及所有父类成员的成分(调用父类成员的拷贝函数)
- 不要尝试在拷贝构造和拷贝赋值之间相互复用,应该向共同技能放在第三方函数内,用两个函数共同调用。