zoukankan      html  css  js  c++  java
  • Effective C++ 条款11:在operator=中处理"自我赋值"

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

    class Widget { ... };
    Widget w;
    ...
    w = w;					// 赋值给自己
    a[i] = a[j];			// 潜在的自我赋值
    *px = *py;				// 潜在的自我赋值
    
    class Base { ... };
    class Derived: public Base { ... };
    void doSomething(const Base& rb, Derived* pd);	// rb和*pd有可能其实是同一对象
    

    尝试自我管理资源

    class Bitmap { ... };
    class Widget {
    	...
    private:
    	Bitmap* pb;			// 指针,指向一个从heap分配而得的对象
    };
    // 一个不安全的operator=实现版本
    Widget& Widget::operator=(const Widget& rhs) {
    	delete pb;						// 停止使用当前的bitmap
    	pb = new Bitmap(*rhs.pb);		// 使用rhs's bitmap的副本
    	return *this;					// 见条款10
    }
    

    可能出现的问题就是,*this和rhs可能是同一个对象,最后会导致自己持有一个指针指向一个已被删除的对象!

    自我安全性

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

    以上代码确实解决了自我赋值的问题,但是会引发异常的问题,如果new Bitmap导致异常了,那么Widget最终会持有一个指针指向一块被删除的Bitmap。

    异常安全性

    Widget& Widget::operator=(const Widget& rhs) {
    	Bitmap* pOrig = pb;						// 记住原先的pb
    	pb = new Bitmap(*rhs.pb);
    	delete pOrig;							// 删除原先的pb
    	return *this;
    }
    

    copy and swap

    class Widget {
    ...
    void swap(Widget& rhs);
    ...
    };
    Widget& Widget::operator=(const Widget& rhs) {
    	Widget temp(rhs);
    	swap(temp);
    	return *this;
    }
    Widget& Widget::operator=(Widget rhs) {	// 注意这里是传值
    	swap(rhs);					
    	return *this;
    }
    

    总结

    1. 确保当对象自我赋值时operator=有良好行为。其中技术包括比较”来源对象”和”目标对象”的地址、精心周到的语句顺序、以及copy-and-swap.
    2. 确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为仍然正确。
  • 相关阅读:
    Wide & Deep Learning for Recommender Systems
    两个经典问题
    Vlog简介
    中文dumps显示
    用Python提取中文关键词
    【STL】算法 — partial_sort
    c字符串分割 strtok()
    JSP的声明(statement)
    layui之ajax巨坑
    jQuery 库中的 $() 是什么?(答案如下)
  • 原文地址:https://www.cnblogs.com/zhonghuasong/p/7443800.html
Copyright © 2011-2022 走看看