剑指offer笔记面试题1----赋值运算符函数
题目:如下为类型CMyString的声明,请为该类型添加赋值运算符函数。
class CMyString{
public:
	CMyString(char* pData = nullptr);
	CMyString(const CMyString& str);
	~CMyString(void);
private:
	char* m_pData;
};
注意点:
- 是否把返回值的类型声明为该类型的引用,并在函数结束前返回实例自身的引用(*this)。只有返回一个引用,才可以允许连续赋值。否则,如果函数的返回值是void,则应用该赋值运算符将不能进行连续赋值。
 - 是否把传入的参数类型声明为常量引用。如果传入的参数不是引用而是实例,那么从形参到实参会调用一次复制构造函数。把参数声明为引用可以避免这样的无谓消耗,能提高代码的效率。同时,我们在复制运算符函数内不会改变传入的实例状态,因此应该为传入的引用参数加上const关键字。
 - 是否释放实例自身已有的内存。如果我们忘记在分配新内存之前释放自身已有的空间,则程序将出现内存泄漏。
 - 判断传入的参数和当前的实例(this)是不是同一个实例。如果是同一个,则不进行复制操作,直接返回。如果事先不判断就进行赋值,那么在释放实例自身内存的时候就会导致严重的问题:当this和传入的参数是同一个实例时,一旦释放了自身的内存,传入的参数的内存也同时被释放了,因此再也找不到需要赋值的内容了。
 
经典的解法,适用于初级程序员
	//当我们完整的考虑了上述4个方面后,可以写出如下的代码:
	CMyString& CMyString::operator=(const CMyString& str){
		if(this == &str)
			return *this;
		delete[] m_pData;
		m_pData = nullptr;
		m_pData = new char[strlen(str.m_pData) + 1];
		strcpy(m_Data, str.m_pData);
		return *this;
	}
考虑异常安全性的解法,高级程序员必备
	/*在前面的函数中,我们分配内存之前先用delete释放了实例m_pData的内存。如果此时内存不足导致new char抛出异常,则m_pData将是一个指针,这样非常容易导致程序崩溃。也就是说,一旦在复制运算符函数内部抛出一个异常,CMyString的实例不在保持有效的状态,这就违背了异常安全性(Exception Safety)原则。要想在赋值运算符函数中实现异常安全性,我们可以先创建一个临时实例,再交换临时实例和原来的实例。下面是这种思路的参考代码:*/
	CMyString& CMyString::operator=(const CMyString& str){
		if(this != &str){
			CMyString strTemp(str);
			char* pTemp = strTemp.m_pData;
			strTemp.m_pData = m_pData;
			m_pData = pTemp;
		}
		return *this;
	}
测试用例:
- 把一个CMyString的实例赋值给另一个实例。
 - 把一个CMyString的实例赋值给它自己。
 - 连续赋值。
 
测试代码:
	void CMyString::Print(){
		printf("%s", m_pData);
	} 
	void Test1(){
		printf("Test1 begins:\n");
		char* text = "Hello world";
		CMyString str1(text);
		CMyString str2;
		str2 = str1;
		printf("The expected result is: %s.\n", text);
		printf("The actual result is: ");
		str2.Print();
		printf(".\n");
	}
	//赋值给自己
	void Test2(){
		printf("Test2 begins:\n");
		char* text = "Hello world";
		CMyString str1(text);
		str1 = str1;
		printf("The excepted result is: %s.\n", text);
		printf("The actual result is: ");
		str1.Print();
		printf(".\n");
	} 
	//连续赋值
	void Test3(){
		printf("Test3 begins:\n");
		char* text = "Hello world";
		CMyString str1(text);
		CMyString str2, str3;
		str3 = str2 = str1;
		printf("The expected result is: %s.\n", text);
		printf("The actual result is: ");
		str2.Print();
		printf(".\n");
		printf("The expected result is: %s.\n", text);
		printf("The actual result is: ");
		str3.Print();
		printf(".\n");
	}
本题考点:
- 考查应聘者对C++基础语法的理解,如运算符函数、常量引用等。
 - 考查与应聘者对内存泄漏的理解。
 - 对于高级C++程序员,面试官还将考查应聘者对代码异常安全性的理解。
 
实现代码:
	#include <cstring>
	#include <cstdio>
	class CMyString{
	public:
		CMyString(char* pData = nullptr);
		CMyString(const CMyString& str);
		~CMyString(void);
		CMyString& operator=(const CMyString& str);
		void Print();
	private:
		char* m_pData;
	};
	CMyString::CMyString(char* pData){
		if(pData == nullptr){
			m_pData = new char[1];
			m_pData[0] = '\0';
		}
		else{
			int length = strlen(pData);
			m_pData = new char[length + 1];
			strcpy(m_pData, pData);
		}
	}
	CMyString::CMyString(const CMyString& str){
		int length = strlen(str.m_pData);
		m_pData = new char[length + 1];
		strcpy(m_pData, str.m_pData);
	}
	CMyString::~CMyString(){
		delete[] m_pData;
	}
	CMyString& CMyString::operator=(const CMyString& str){
		if(this == &str)
			return *this;
		delete[] m_pData;
		m_pData = nullptr;
		m_pData = new char[strlen(str.m_pData) + 1];
		strcpy(m_pData, str.m_pData);
		return *this;
	}
	int main(){
		Test1();
		Test2();
		Test3();
		return 0;
	}
												
											剑指offer笔记面试题1----赋值运算符函数的更多相关文章
- 剑指offer笔记面试题2----实现Singleton模式
		
题目:设计一个类,我们只能生成该类的一个实例. 解法一:单线程解法 //缺点:多线程情况下,每个线程可能创建出不同的的Singleton实例 #include <iostream> usi ...
 - 剑指offer笔记面试题3----数组中重复的数字
		
题目一:找出数组中重复的数字.在一个长度为n的数组里的所有数字都在0~n-1的范围内.数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次.请找出数组中任意一个重复的数字.例如 ...
 - 剑指offer笔记面试题4----二维数组中的查找
		
题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 测试用例: 二维数组中包含 ...
 - 剑指offer笔记面试题5----替换空格
		
题目:请实现一个函数,把字符串中的每个空格替换成"20%".例如,输入"We are happy."则输出"We%20are%20happy.&quo ...
 - 剑指offer笔记面试题6----从未到头打印链表
		
题目:输入一个链表的头结点,从尾到头反过来打印出每个结点的值.链表节点定义如下: struct ListNode{ int m_nKey; ListNode* m_pNext; } 测试用例: 功能测 ...
 - 剑指offer笔记面试题7----重建二叉树
		
题目:输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如,输入前序遍历序列{1, 2, 4, 7, 3, 5, 6, 8}和中序遍历序列 ...
 - 剑指offer笔记面试题8----二叉树的下一个节点
		
题目:给定一棵二叉树和其中的一个节点,如何找出中序遍历序列的下一个节点?树中的节点除了有两个分别指向左.右子节点的指针,还有一个指向父节点的指针. 测试用例: 普通二叉树(完全二叉树,不完全二叉树). ...
 - 剑指offer笔记面试题9----用两个栈实现队列
		
题目:用两个栈实现一个队列.队列的声明如下,请实现它的两个函数appendTail和deleteHead,分别完成在尾部插入节点和在队列头部删除节点的功能. 测试用例: 往空的队列里添加.删除元素. ...
 - 剑指offer笔记面试题10----斐波那契数列
		
题目:求斐波那契数列的第n项.写一个函数,输入n,求斐波那契数列的第n项.斐波那契数列的定义如下:f(0) = 0, f(1) = 1,f(n) = f(n - 1) + f(n - 2). 测试用例 ...
 
随机推荐
- 第九次作业——DFA最小化,语法分析初步
			
老师:MissDu 提交作业 1.将DFA最小化:教材P65 第9题 答: 2.构造以下文法相应的最小的DFA S→ 0A|1B A→ 1S|1 B→0S|0 3.自上而下语法分析,回溯产生的原因是 ...
 - Cypher基本指令学习1
			
1.查询节点 查询所有节点match (n) return n 查询带有标签的节点 match(movie:Flyer) return movie.name 查询关联节点(查询A导演的所有电影) ma ...
 - usb fx2  cy68013 Cyapi使用心得
			
Cyapi使用心得(1)--USB连接 用Cyapi也有一阵了,这个确实比EZusb的api好用,简单说下Cyapi的使用心得,在编程中应该注意的一些问题,毕竟,说起来,那个CYapi的说明文档讲的实 ...
 - 【Hybird】274-Hybird App 应用开发中 5 个必备知识点复习
			
前言 我们大前端团队内部 ?每周一练 的知识复习计划还在继续,本周主题是 <Hybird APP 混合应用专题> ,这期内容比较多,篇幅也相对较长,每个知识点内容也比较多. 之前分享的每周 ...
 - css修改overflow滚动条默认样式
			
html代码 <div class="inner"> <div class="innerbox"> <p style=" ...
 - 自动化运维之SaltStack实践
			
自动化运维之SaltStack实践 1.1.环境 linux-node1(master服务端) 192.168.0.15 linux-node2(minion客户端) 192.168.0.16 1.2 ...
 - 带你使用Visual Studio 2019创建一个MVC Web应用
			
工欲善其事必先利其器,我们既然有Visual Studio2019这样的IDE为什么不用?学.Net Core而不用Visual Studio进行开发可谓是多么另类呀!既然你已经安装了VS2019的话 ...
 - 如何在Android手机上进行自动化测试(下)
			
版权声明:允许转载,但转载必须保留原链接:请勿用作商业或者非法用途 前言 通过阅读本篇教程,你将会了解到: 如何使用Poco对Android原生应用进行测试 Poco支持直接对任何Android原生应 ...
 - 《Java基础知识》Java异常处理详解
			
1. Java 中的异常 前言:Java 中的异常处理是处理程序运行错误时的强大机制之一,它可以保证应用程序的正常流程. 首先我们将了解java异常.异常的类型以及受查和非受查异常之间的区别. 1.1 ...
 - Nginx优化之一
			
一.Nginx安全优化 1.1:隐藏nginx版本信息 官方配置参数说明:http://nginx.org/en/docs/http/ngx_http_core_module.html#server_ ...