你的赋值操作符能正确地将对象赋给对象本身吗?
来源:互联网 发布:linux修改root密码命令 编辑:程序博客网 时间:2024/05/22 17:30
我们在写operator= 函数实现时,要注意一个问题:要考虑对象自我赋值的情况,因为客户完全可以写
下如下代码:
- Widget w;
- ...
- w=w;
这样写完全合法,那么我们在写Widget::operator=(xx)的实现时,一定要考虑到这个问题,否则一些想象不到的问题就来"拜访"你了,呵呵,比如,现在有一个类Widget:
- class Bitmap{};
- class Widget{
- public:
- ...
- Widget& operator=(const Widget& rhs){
- delete hBitmap_;//hBitmap_可能为NULL,注意:delete 删除NULL指针是可以的,它会什么都不做.
- hBitmap_ = new Bitmap(*rhs.hBitmap_);
- return *this;
- }
- private:
- Bitmap* hBitmap_;
- };
这里的rhs与*this如果要是同一个对象,会出现什么问题?也就是说两个对象的hBitmap_是同一个图片
数据,当delete hBitmap_;被执行时,它们指向的同一个Bitmap资源被释放掉,紧接着执行下面一条语句就出
现了问题,因为新产生的hBitmap_是一个无效对象(它占用的资源对象已经被释放掉了).程序继续往下跑的时
候就会可能出现访问内存等问题.这个时候你注意到了这个问题,你开始修改代码:
- Widget& Widget::operator=(const Widget& rhs){
- if(this == &rhs){ //增加了判断条件
- return *this;
- }
- delete hBitmap_;
- hBitmap_ = new Bitmap(*rhs.hBitmap_); // throw possibel exception?
- return *this;
- }
代码增加了逻辑判断语句,这样就解决了"自我赋值安全"问题,然而如果new Bitmap(*rhs.hBitmap_);这条语
句出现了异常,那么hBitmap_就是一个不可预料值,这样就很可怕,导致了"异常性安全"问题的出现.
往往让operator=获得了"异常安全性"却会自动获得"自我赋值安全"的回报,所以很多人把焦点放在了"异常安全性",
而对于"自我赋值安全性"就放任其不管,于是他们想出这样的方案:在赋值之前先不去删除以前的对象.这样就写出
如下代码:
- Widget& Widget::operator=(const Widget& rhs){
- Bitmap* holdBitmap_ = hBitmap_;
- hBitmap_ = new Bitmap(*rhs.hBitmap_);
- delete holdBitmap_;
- return *this;
- }
这样的话,如果"new Bitmap(*rhs.hBitmap_);"抛出异常,左右操作对象都保持不变,保持了"异常安全性",而它也保持
了"自我赋值安全性",这行得通,不过你要是考虑到效率问题的话,有一种注重"异常安全性"的替代方案将是你的更好的
选择,它是通过"copy and swap"实现的(条款29将会做更详细的探讨):
- class Widget{
- public:
- Widget& operator=(const Widget& rhs){
- Widget tempt(rhs); //make a source copy
- swap(rhs);
- return *this;
- }
- ...
- private:
- void swap(const Widget& rhs); //交换两个Widget对象数据
- ...
- };
由于改实现要将产生一个参数的副本所以说我们可以通过"pass by value"来传递参数,我们再次改写代码:
- class Widget{
- public:
- Widget& operator=(Wiget rhs){
- swap(rhs);
- return *this;
- }
- ....
- private:
- void swap(const Widget& rhs); //交换两个Widget对象数据
- ...
- };
这样的函数签名看起来虽然看起来让人不是那么舒服,虽然它为了巧妙的修改代码却牺牲了代码可读性,然而将
"copying动作"从函数本体移至"函数参数构造阶段"却可令编译器有时生成更高效代码.
请记住:
◆ 确保当对象自我赋值时operator=有良好行为.其中技术包括比较"来源对象"和"目标对象"的地址、精心周到的语
句顺序、以及copy-and-swap.
◆ 确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为仍然正确.
- 你的赋值操作符能正确地将对象赋给对象本身吗?
- 正确地将对象赋值给对象本身了吗?
- 将JSON对象、数组的值赋给另外一个对象,(互不影响) 对象赋值
- OC将对象赋给对象,及对象用对象初始化的内存地址变化
- xml 将解析的文件里的值赋给对象,将对象存入集合
- 当给16位的unsigned short 对象赋值100000,赋的值是什么?
- 将一个类的对象的值,赋给另一对象
- C++中关于将对象赋值给整形的过程。
- 如何将一个对象赋值给指定类型的数据?
- 转换运算符技巧之将对象赋值给整数
- 将构造函数的作用域赋给新的对象
- 将一个 vector 赋给另一个 vector(迭代器的运用)_初学vector对象3
- 通过反射将一个对象的值赋给另一个对象中对应的属性 不需要用set、get
- 将子类对象赋值给父类对象
- Java将子类对象赋值给父类对象
- 关于将一个对象赋值给另一个对象
- 浅谈将子类对象赋值给父类对象
- 将一个对象的属性值赋给另一个对象的相同的属性 这两个对象必须都符合javaBean的标准
- Eclipse中Tab设置为4个空格
- Android背后的恶意应用,您应该知道的事
- Tomcat、JAVA、Iframe、P3P跨域
- MS SQL数据导入MySQL
- AT编程常见问题
- 你的赋值操作符能正确地将对象赋给对象本身吗?
- .NET技术与Ajax技术结合的四种方式
- 累
- JOGL in Eclipse
- jquery ajax表单提交插件
- Linux启动或禁止SSH用户及IP的登录
- Loadrunner网络延迟
- 自己编写的Objective-c的singleton单例实例
- 关于条件变量的一点理解