笔记:条款11: 在operator= 中处理“自我赋值”

本文通过示例详细解析了C++中自我赋值和异常安全的问题,包括不安全版本的问题展示、自我赋值安全但异常不安全的改进方案,以及最终实现既自我赋值安全又异常安全的代码实现。

这是我在阅读Effective c++中认为比较重要的部分,下面给出了我对这一节的理解,并写出对应的比较容易理解的代码。

有一份自我赋值不安全和异常不安全的代码如下:

class Bitmap {

};
class Widget {
private:
	Widget(Bitmap*pb):p(pb){ }
	Bitmap* p;  //指向一个从heap分配而得的对象。
	Widget& operator = (const Widget&rhs);
};
Widget& Widget::operator=(const Widget&rhs) {
	delete p;
	p = new Bitmap(*(rhs.p));
	return *this;
}

当自我赋值时,delete删除了自身对象,最终发现自己持有一个指针指向一个已被删除的对象。

自我赋值安全,但不是异常安全的版本,加上

if (this == &rhs) return *this;

如果new Bitmap导致异常,不论是因为分配时内存不足或因为Bitmap的构造函数抛出异常,widget最终都会持有一个指针指向一块被删除的bitmap(针对上面的例子)

 

异常安全+自我赋值安全版本

Widget& Widget::operator=(const Widget&rhs) {
	Bitmap*temp = p; //记住原先的p
	p = new Bitmap(*rhs.p);//产生新的p
	delete temp;//删除原来的
	return *this;
}

如果new抛出异常,p保持现状,也能处理自我赋值。

请记住

确保当对象自我赋值时operator = 有良好行为。其中技术包括比较“来源对象”和“目标对象”的地址、精心周到的语句顺序、以及copy-and-swap.

确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为仍然正确。

在 C++ 中,`std::vector` 的赋值操作符(`operator=`)是完全可用的,标准库为 `std::vector` 提供了多种赋值操作的重载形式,包括复制赋值和移动赋值。如果在使用过程中遇到赋值操作符不可用的情况,通常是由于以下几种原因之一: ### 1. 元素类型不可复制或不可赋值 如果 `std::vector` 中存储的元素类型没有定义复制赋值操作符(即该类型的 `operator=` 被删除或私有化),那么整个 `std::vector` 的赋值操作也将无法进行。例如: ```cpp struct NonAssignable { NonAssignable& operator=(const NonAssignable&) = delete; }; std::vector<NonAssignable> vec1, vec2; vec2 = vec1; // 错误:无法调用被删除的赋值操作符 ``` 在这种情况下,编译器会报错,指出无法执行赋值操作[^1]。 ### 2. 使用了 `const` 限定的 vector 如果尝试对一个 `const std::vector` 执行赋值操作,那么赋值操作将被禁止,因为 `const` 对象的成员函数只能调用 `const` 成员函数,而赋值操作符是非 `const` 的: ```cpp const std::vector<int> vec1 = {1, 2, 3}; std::vector<int> vec2; vec2 = vec1; // 正确 vec1 = vec2; // 错误:不能对 const 对象赋值 ``` ### 3. 使用了不兼容的容器类型 试图将一个非 `std::vector` 类型的对象赋值给 `std::vector` 会导致编译错误。例如,尝试将 `std::list` 赋值给 `std::vector` 是不允许的: ```cpp std::vector<int> vec; std::list<int> lst = {1, 2, 3}; vec = lst; // 错误:不能将 std::list 赋值给 std::vector ``` ### 4. 编译器版本或标准限制 在极少数情况下,如果使用的是非常旧的编译器(例如不支持 C++11 或更高版本),可能会遇到 `std::vector` 的移动赋值操作符不可用的问题。C++11 引入了移动语义,增强了 `std::vector` 的赋值行为,包括支持移动赋值操作符。 ### 解决方法 - 确保元素类型是可复制赋值的。 - 避免对 `const std::vector` 执行赋值。 - 确保赋值的类型匹配,或使用 `assign` 成员函数进行赋值。 - 使用支持 C++11 或更高版本的编译器以获得完整的 `std::vector` 功能。 ### 示例:使用 `assign` 替代赋值操作符 ```cpp std::vector<int> vec1 = {1, 2, 3}; std::vector<int> vec2; vec2.assign(vec1.begin(), vec1.end()); // 使用 assign 替代赋值操作符 ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值