条款11(一):在operator= 中处理“自我赋值”

发布时间:2025-05-18 04:34

笑话11: 每天早上看到镜子中的自己说:‘早安,我又赢了一天的颜值大战!’ #生活乐趣# #日常生活趣事# #日常生活笑话# #轻松幽默一刻#

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

Handle assignment to self in operator=.
本章较长,分为两部分。

自我赋值

“自我赋值”发生在对象被赋值给自己时:

class Widget { ... }; Widget w; ... w = w; //赋值给自己12345

虽然这种做法看起来比较傻,但是这种操作却是合法的。
此外,自我赋值并不是总是可以一眼分辨出来,例如:

a[i] = a[j]; //潜在的自我赋值1

如果i和j具有相同的值时,这就是一个自我赋值。再比如:

*px = *py; //潜在的自我赋值1

如果指针px和py恰巧指向同一个东西,这也是一个自我赋值。

这些并不明显的复制行为,是“别名(aliasing)”所带来的结果。所谓“别名”:

别名就是有一个以上的方法指称(指涉)某对象。

一般而言,如果某段代码操作pointers或references而它们被从来“指向多个相同类型的对象”,就需要去考虑这些对象是否为同一个对象。
实际上,两个对象只要来自同一个继承体系,它们甚至不需要声明为相同类型就可能会造成“别名”,因为一个base class的reference或者pointer可以指向一个derived class对象:

class Base { ... }; class Derived : public Base { ... }; void doSomethings(const Base& rb, Derived* pd); //rd和*pd有可能其实是同一个对象123

在这里,假如说我们尝试自行管理资源(即打算写一个用于资源管理的class,就需要这样做),就可能会掉进“在停止使用资源之前意外释放了它”的陷阱。举个例子,假如建立一个class用来保存一个指针指向一块动态分配的位图(bitmap):

class Bitmap { ... }; class Widget { ... private: Bitmap* pb; //指针,指向一个从heap分配而得的对象 };123456

接着,下面的operator= 的实现代码,看起来虽然合理,但是在进行自我赋值时并不安全

Widget& Widget::operator=(const Widget& rhs) //不安全的operator= 的实现版本 { delete pb; //停止使用当前的bitmap pb = new Bitmap(*rhs.pb); //使用rhs's bitmap的副本(复件) return *this; }123456

之所以会出现自我赋值的问题,operator= 函数内的*this(赋值的目的端)和rhs有可能是同一个对象。如果它们是同一个对象,那么delete对象就不只是销毁当前对象的bitmap,它也同时销毁了rhs的bitmap。
因此,在函数末尾,对于Widget,它原本不应该被自我赋值动作改变的,然而此时:

Widget发现自己持有一个指针,指向一个已经被删除的对象。

想要阻止这样的错误,传统的做法是:

operator= 最前面进行一个“证同测试(identity test)”,以此达到自我赋值的检验目的

Widget& Widget::operator=(const Widget& rhs) { if(this == &rhs) //证同测试(identity test) return *this; //如果是自我赋值,就不做任何事情 delete pb; pb = new Bitmap(*rhs.pb); return *this; }12345678

这种解决办法是行得通的。在第一个版本的operator= 中,不仅不具备“自我赋值安全性”,也不具备“异常安全性”,然而,这个新版本的operator=,仍然存在异常方面的问题
如果“new BItmap”导致了异常(比如因为分配时内存不足或者因为Bitmap的copy构造函数抛出异常),Widget最终会持有一个指针指向一个被删除的Bitmap。这样的指针是有害的:

既不能安全的删除它,也不能安全的读取它。

唯一能对它们做的安全的事情就是付出很多调试的功夫,去找到错误的起源。

网址:条款11(一):在operator= 中处理“自我赋值” https://www.yuejiaxmz.com/news/view/990803

相关内容

OpenAI推出智能体Operator:解放你的网络生活,立即体验自动化任务处理!
编写高质量代码——重载operator=的标准三步走
OpenAI推出新型AI代理Operator,重新定义自动化任务执行方式
C++11中的=delete,=default
OpenAI发布AI智能体Operator,自动化日常任务的未来就在眼前!
OpenAI发布首个AI智能体Operator:自动化任务的未来与挑战
OpenAI Operator上线:AI智能体助力自动化网购与订票
OpenAI即将推出“Operator”智能体:自动化任务的新纪元
新AI助理来袭!OpenAI的Operator将如何改变你的生活?
C++ operator关键字(重载操作符)

随便看看