IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 在operator=中处理自我赋值 -> 正文阅读

[C++知识库]在operator=中处理自我赋值

注意自我赋值

class MyClass{//...};
Myclass m;
m = m; //自我赋值
  • 你可能认为自己不会写出这样的代码,确实,这样显然的自我赋值让我嗤之以鼻。但是因为指针和引用的存在,存在着隐晦的自我赋值。
  • 而且因为继承的存在,Base对象和Derive的指针和引用天然的就可能是同一对象。
MyClass m;
MyClass* p1 = &m;
MyClass* p2 = &m;
*p1 = *p2; //指针的隐性自我赋值

MyClass& r1 = m;
MyClass& r2 = m;
r1 = r2;  //引用的隐性自我赋值
  • 这些已经很不妙了,但是还有更糟糕的情况。

自我赋值安全问题

  • 如果你尝试手动管理资源,可能会掉入一个陷阱:停止使用资源前将其释放。
class MyClassNode{
	vector<int> _v;
	int _num;
public:
//略...
};
class MyClass{
private:
	MyClassNode* _pM;
public:
	MyClass& operator=(const MyClass& m){
		delete _pM; //如果this == &_pM,想一想有什么问题?
		_pM = new MyClass(*m._pM);
		return *this;
	}
};
  • MyClass类中封装一个指针。
  • 在operator=中,我们只需要delete指针,然后拷贝指针即可。但是这段代码是有问题的。倘若你自己给自己赋值比如m = m;
  • 那么你在delete _pM的时候已经将m._pM销毁了,那么你哪来的m._pM用于赋值呢?

证同测试

  • 我们的一种解决方法是加个判断,如果是自我赋值,那么就直接return。
class MyClass{
public:
	MyClass& operator=(const MyClass& m){
		if(&m == this){  //自我赋值,直接return
			return *this;
		}
		else{
			delete _pM;
			_pM = new MyClass(*m._pM);
			return *this;
		}
	}
};
  • 这种手段也叫做证同测试。证同测试可以很好的解决这个问题。

异常安全问题

  • 但是我们仍有一个问题,而且这个问题是个广泛的问题:异常安全。如果我们在new的时候出现异常,但是_pM已经被我们delete掉,我们的operator=函数被迫终止,但是却改变了*this。
  • 实际上,我们只需要略微注意语句的顺序,就可以解决这个问题。比如,使用一个临时对象保持_pM。先赋值,再delete。
class MyClass{
public:
	MyClass& operator=(const MyClass& m){
			MyClass* temp = _pM; //保持_pM的资源
			_pM = new MyClass(*m._pM);
			delete temp;
			return *this;
	}
};
  • 你可能会感到疑惑,因为我去掉了证同测试。你带着疑惑去重新检测,如果是自我赋值…你发现,我们解决了异常安全问题的同时,竟然解决了自我赋值安全问题!!而更让人高兴的是,这两个问题往往是关联着的,也就是说,大部分情况下,解决了异常安全问题就足矣。
  • 你可能会说,但是面对自我赋值时,证同测试的效率会高。哦,确实是的。但是你要知道,证同测试同样需要代价。而operator=调用的越多,代价越大。你应该仔细考量,是否为了自我赋值加上证同测试。

copy-and-swap技术

  • 而解决异常安全问题的另外一种方法就是copy-and-swap技术。也就是我们常说的现代C++的operator=写法。
class MyClass{
public:
	MyClass& operator=(const MyClass& m){
			MyClass temp(m);
			swap(_pM, temp._pM);
			return *this;
	}
};
  • 我们利用temp对象做一个中转。没有异常安全问题,因为构造函数和swap函数都应该是异常安全的。
  • 而还有更简洁的写法,
class MyClass{
public:
	void swap(MyClass& m){//...}
	MyClass& operator=(MyClass m){ //pass-by-value
			swap(m._pM);
			return *this;
	}
};
  • 每错,以值传递,m已经是一份副本。我们直接交换即可。

本文主要来自: 《EffectiveC++》。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-12-13 12:37:21  更:2021-12-13 12:38:40 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:44:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码