博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++重载赋值运算符
阅读量:6976 次
发布时间:2019-06-27

本文共 1930 字,大约阅读时间需要 6 分钟。

这是一道C++的面试题,下面在这篇博客中分析一下这个问题。先上题目:

//题目:如下为类型CMyString的声明,请为该类型添加赋值运算符函数。class CMyString{public:CMyString(char *pData=NULL);//构造函数CMyString(const CMyString& str);//拷贝构造函数~CMyString();//析构函数private:char* m_pData;//数据域,字符指针};

  

拿到这个题目,如果你看过effective C++这本书,代码应该很容易就能够完成,在写的时候要注意下面的一个要点:

1>赋值运算符要返回该实例自身的引用(*this),因为只有返回一个引用才可以允许连续赋值操作。

2>把传入的参数的类型声明为常量引用,这样能够避免传入实例时的值拷贝,避免复制构造函数的调用。同时赋值运算符不会改变传入的实例的状态,因此要在传入的参数前加上const关键字。

3>要在分配新的内存之前释放自身已有的空间,否则程序会出现内存泄露。赋值运算符执行的是赋值操作,在赋值运算符之前肯定调用过对象的构造函数或者拷贝构造函数,因为一个对象在实例化的时候肯定会有一个初始化的过程。这里必须释放原来的堆内存空间,因为m_pData可能变得更长了,原来的空间可能已经不够用了

4>判断传入的参数和当前的实例(*this)是不是同一个实例,如果是同一个实例的话就直接返回,防止str1=str1这样的没有意义的操作。如果不判断这个 ,结果很严重,如果释放了实例的堆内存空间,也就等于释放了参数的堆空间(虽然参数是const的,但是这次的释放是通过this对象释放的,不是通过参数对象释放的),就没有了这个对象的完整备份,那么这个对象就永远的从这个世界上消失了。

CMyString& CMyString::operator=(const CMyString& str){	if(this == &str)	{		return *this;	}	delete[] m_pData;	m_pData = NULL;	m_pData = (char*)malloc(strlen(str.m_pData) + 1);	strcpy(m_pData, str.m_pData);	return *this;}

  上面的代码虽然能够解决问题,但是存在安全隐患,在分配内存之前先用delete释放了实例m_pData的内存,如果此时内存不足,导致new char申请内存失败,m_pData将是一个空指针,这很容易发生异常,因为我们认为它不是一个空指针。

这里要处理的是防止new堆内存的时候,由于内存不足等原因导致异常,而是当前对象的完整性遭到破坏。也就是说你要异常要在操作当前对象之前,不能在操作当前对象的过程中异常,使得这个当前对象不完整。

解决的办法有两种:

1>先用new分配新内容,然后再用delete释放已有内容,也就是分配成功之后再分配新的内容,这样就能保证在分配失败之后,原来的CMyString的实例不会被修改。

2>先在栈中创建一个临时实例,然后在交换临时实例和原有实例

下面给出2>的代码实现:

CMyString& CMyString::operator=(const CMyString& str){	if(this == &str)	{		return *this;	}	CMyString tempStr(str);	//交换临时实例和原有实例的指针指向	char *pData = tempStr.m_pData;	tempStr.m_pData = m_pData;	m_pData = pData;	return *this;}

  注意代码的技巧的地方在于,这个tempStr是在栈中开辟的临时的实例,在这个函数运行结束以后,这个函数栈要销毁,所以tempStr的析构函数会自动的调用,当析构函数调用的时候肯定会自动的释放原来的那块堆内存的。

在新的代码中,在CMyString的构造函数里用new分配内存。如果由于内存不足抛出如bad_alloc等异常,我们还没有修改原来的实例的状态,因此实例的状态还是有效的。

其实上面的代码应该有try-catch模块,这样就能处理异常,同时不会是程序终止。改进的实现的唯一目的就是为了保证在抛出异常(可能因为内存不足)时,原来的实例没有被修改过。也就是说,要抛异常你就早点抛,在我修改原来实例之前就抛,要么你就不要抛。

转载于:https://www.cnblogs.com/stemon/p/4625407.html

你可能感兴趣的文章
android ImageLoader加载本地图片的工具类
查看>>
安全的发布 .NET 应用的改动到产品服务器环境
查看>>
解析含有资源类型的字符串
查看>>
C#:简单递归累加算法
查看>>
day13_H5_CSS_2
查看>>
Sass (Syntactically Awesome StyleSheets)
查看>>
ASN.1探索 - 3 编码规则与传输语法(3 - PER)(转)
查看>>
Jmeter+ant+jenkins集成
查看>>
使用 DX 编译 Android应用
查看>>
第一章:Nginx安装
查看>>
React-Native学习指南
查看>>
用cssText属性批量操作样式
查看>>
C语言 Web实时消息后台服务器推送技术---GoEasy
查看>>
警惕javascript变量的全局污染问题
查看>>
response小结(三)—输出随机图片(验证码功能实现)
查看>>
【CentOS7】LINUX下面桌面的安装
查看>>
如何禁止浏览器自动填充非登陆input的账号和密码?
查看>>
jquery(ajax)+ashx简单开发框架(原创)
查看>>
Georgia Tech- 新的篇章
查看>>
易错~~
查看>>