Effective C++——关于重载赋值运算

发布时间:2024年01月24日

令operator=返回一个*this的引用

? ? ? ? 在重载=,+=,*=等运算符时,令其返回一个指向this的引用。

class MyClass {
	int* val;
public:
	MyClass(int i) : val(new int(i)){}
	MyClass():val(new int(0)){}

	void print() {
		cout << *val << endl;
	}

	MyClass& operator=(const MyClass& m) {
        delete val;
		val = new int(*m.val);
		return *this;
	}
};

? ? ? ? 这种情况可以实现连锁赋值。

MyClass a,b;
MyClass c(32);

a = b = c;

在重载赋值运算符时处理“自我赋值”

? ? ? ? 上面的代码,我们做如下的尝试。

? ? ? ? 在执行b=b时,因为两个对象指向同一块内存,在执行delete val语句时,会将内存释放掉。这样的做法无疑是有问题的。

? ? ? ? 正常的代码中,自我赋值出现的概率很小,但是隐性的自我赋值可能会出现。例如,

list[i] = list[j];
*px = *py;
void func(BaseClass* base, DerivedClass* derived){...}

? ? ? ? 其中i=j时,list[i] 与 list[j]相同;px与py相同时,指向同一块内存;而父类指针与子类指针甚至可以同时指向同一个子类对象。

? ? ? ? 如果在以上这种隐式的自我赋值的情况出现时,会给调试带来很大困难。我们用两种方式来避免这种情况:

? ? ? ? 1,在深度复制前检测是否相同

class MyClass {
	int* val;
public:
	MyClass(int i) : val(new int(i)){}
	MyClass():val(new int(0)){}

	void print() {
		cout << *val << endl;
	}

	MyClass& operator=(const MyClass& m) {
        if(this == &m)
            return *this;
        delete val;
		val = new int(*m.val);
		return *this;
	}
};

? ? ? ? 如果两个地址相同,那么就什么都不做,直接返回*this。

? ? ? ? 2,用其他指针来销毁空间

	MyClass& operator=(const MyClass& m) {
		int* temp = m.val;
		val = new int(*m.val);
		delete temp;
		return *this;
	}

? ? ? ? 在销毁val之前,用临时指针temp来代替val,然后在val修改之后,通过temp来释放空间。这样就保证了自我赋值的正确性。

? ? ? ? 建议使用第二种方式

? ? ? ? 因为,这样避免了异常带来的影响。如果在new 的过程中出现异常,第二种方式保证了val指向可用的数据。而第一种方法会先销毁val,而new的过程如果出现异常,val会指向不明确的内存。

文章来源:https://blog.csdn.net/A11en3/article/details/135825638
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。