• effective C++ 读书笔记 条款11


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

    在实现operator=时考虑自我赋值是必要的就像 x=y 。我们不知道变量x与y代表的值是否为同一个值(把x和y说成是一个指针更恰当一点)。

    例如以下

    第一版:

    #include <iostream>
    
    using namespace std;
    
    class bitmap
    {
    public:
    	bitmap()
    	{
    		cout<<"调用bitmap()无參构造函数"<<endl;
    	}
    	bitmap(const bitmap& bt)
    	{
    		this->i = bt.i;
    		cout<<"调用bitmap()拷贝构造函数"<<endl;
    	}
    	~bitmap()
    	{
    	}
    private:
    	int i;
    };
    class Widget
    {
    public:
    	Widget()
    	{
    		pb = new bitmap();
    	}
    	Widget(const Widget& wd)
    	{
    		this->pb = wd.pb;
    	}
    public:
    	Widget& operator=(const Widget& rhs);
    private:
    	bitmap* pb; //定义一个从heap分配而得的对象
    };
    
    //第一版赋值函数:
    Widget& Widget::operator=(const Widget& rhs)
    {
    	delete pb;
    	pb = new bitmap(*rhs.pb);
    	return *this;
    }
    //这一版函数的pb在使用前清理掉之前的pb指向。再接受一个new出来的新对象,看着非常顺理成章,可是
    //当this与函数參数rhs相等的时候,pb = new bitmap(*rhs.pb);由于我们已经把*rhs.pb delete掉了。

    int main() { Widget w1; Widget w2; w1 = w2; return 0; } /* 调用bitmap()无參构造函数 调用bitmap()无參构造函数 调用bitmap()拷贝构造函数 Press any key to continue */


    第二版:

    //第二版赋值函数:
    Widget& Widget::operator=(const Widget& rhs)
    {
    	if (this == &rhs)
    	{
    		return *this;
    	}
    
    	delete pb;
    	pb = new bitmap(*rhs.pb);
    	return *this;
    }
    //这个版本号行的通,赋值函数基本上是能够接受的,可是不见得是安全的,由于当new产生异常时pb依旧是一个
    //不确定的指针。


    第三版:

    //第三版赋值函数:
    Widget& Widget::operator=(const Widget& rhs)
    {
    	bitmap *pOrig = pb;
    	pb = new bitmap(*rhs.pb);
    	delete pOrig;
    	return *this;
    }
    //第三版函数在開始的时候用pOrig记录了pb。当new没有异常时我们再把pb原来的指向空间释放掉
    //从而提高了安全性。这样的方法也相同可以处理自我赋值。假如这里rhs=*this。我们先对原来的
    //bitmap做了一份备份,删除原bitmap后,指向了我们的那一份备份,也许这样的处理自我赋值的方法
    //不是非常好。可是行的通,在保证安全性的情况下採用这样的办法非常不错。
    


     

    第四版:

    #include <iostream>
    
    using namespace std;
    
    class bitmap
    {
    public:
    	bitmap()
    	{
    		cout<<"调用bitmap()无參构造函数"<<endl;
    	}
    	bitmap(const bitmap& bt)
    	{
    		this->i = bt.i;
    		cout<<"调用bitmap()拷贝构造函数"<<endl;
    	}
    	~bitmap()
    	{
    	}
    private:
    	int i;
    };
    class Widget
    {
    public:
    	Widget()
    	{
    		cout<<"调用Widget()无參构造函数"<<endl;
    		pb = new bitmap();
    	}
    	Widget(const Widget& wd)
    	{
    		cout<<"调用Widget()拷贝參构造函数"<<endl;
    		this->pb = wd.pb;
    	}
    	void my_swap(Widget& rhs);
    public:
    	Widget& operator=(const Widget& rhs);
    private:
    	bitmap* pb; //定义一个从heap分配而得的对象
    };
    
    //第四版赋值函数:
    
    void Widget::my_swap( Widget& rhs)
    {
    	pb = rhs.pb;
    }
    
    Widget& Widget::operator=(const Widget& rhs)
    {
    	Widget temp(rhs);//防止改变rhs
    	my_swap(temp);
    	return*this;
    }
    //第四版赋值函数利用的是copy and swap技术,这个技术在条款29其中
    //有具体说明。还没认真看,这里就不解释了。
    
    //第四版也能够这样用:
    Widget& Widget::operator=(Widget rhs)
    {
    	my_swap(rhs); //事实上本质上是一样的,由于传递的參数是值传递,所以这里传递的是rhs的一个副本。相当于Widget temp(rhs);主要就是防止rhs被改变。
    	return*this;
    }
    
    
    int main()
    {
    	
    	Widget w1;
    	Widget w2;
    	w1 = w2;
    	return 0;
    }
    /*
    调用Widget()无參构造函数
    调用bitmap()无參构造函数
    调用Widget()无參构造函数
    调用bitmap()无參构造函数
    调用Widget()拷贝參构造函数
    Press any key to continue
    */


    总结:

    1:确保当对象自我赋值时 operator= 有良好行为,当中技术包含比較“原来对象”和“目标对象”的地址。、精心周到的语句顺序,以及copy and swap

    2:确定不论什么函数假设操作一个以上的对象,而当中多个对象是同一个对象时,其行为仍然正确。

  • 相关阅读:
    9.算术运算符
    7.字符串格式化
    下载和配置JDK
    Set-常用API及详解
    List-ApI及详解
    电路交换、报文交换、分组交换比较
    集合之List—ArrayList
    java的getClass()函数
    Object类、包装类、内部类详解
    接口的探究
  • 原文地址:https://www.cnblogs.com/wzjhoutai/p/7103522.html
Copyright © 2020-2023  润新知