问题:给出如下CMyString的声明,要求为该类型添加赋值运算符函数。

class CMyString
{
public:
    CMyString(char* pData = NULL);
    CMyString(const CMyString& str);
    ~CMyString(void);
      
private:
    char* m_pData;
};

当面试官要求应聘者定义一个复制运算符函数时,他会关注如下几点:

·         是否把返回值的类型声明为该类型的引用,并在函数结束前返回实例自身(即*this)的引用?只有返回一个引用,才可以允许连续赋值。否则如果函数的返回值是void,假设有三个CMyString的对象,str1、str2和str3,在程序中语句str1=str2=str3将不能通过编译。

·         是否把传入的参数的类型声明为常量引用?如果传入的参数不是引用而是实例,那么从形参到实参会调用一次构造拷贝函数。把参数申明为引用可以避免这样的无谓消耗,能提高代码的效率。同时,我们在赋值运算符函数内是不会改变传入的实例的状态的,因此应该为传入的引用参数加上const关键字。

·         是否记得释放实例自身已有的内存?如果忘了在分配新内存之前释放自身已有的空间,将出现内存泄露。

·         是否判断传入的参数是不是和当前的实例(*this)是不是同一个实例?如果是同一个,则不进行赋值操作,直接返回。如果事先不判断,就进行赋值,那么在释放实例自身的内存的时候就会导致严重的问题:当*this和传入的参数是同一个实例时,那么一旦释放了自身的内存,传入的参数的内存也同时被释放了,因此再也找不到需要赋值的内容了。

当我们完整地考虑了上述几方面之后,我们可以写出如下的代码:

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

这是一般C++教材上提供的参考代码。如果是面试的是应届毕业生或者C++初级程序员,如果能全面地考虑到前面四点并完整地写出代码,面试官可能会让他通过这轮面试。但如果面试的是C++的高级程序员,面试官可能会提出更高的要求。

面试官会提醒我们在前面的函数中,显示地用delete释放自身m_pData的内存。同时我们也会在析构函数中用delete释放自身m_pData的内存。如果这个类型中添加新的指针成员变量,那么我们至少需要做两处修改,即同时在析构函数和这个赋值运算符函数里添加一条delete语句来释放新指针所指向的内存。一个改动需要在代码中多个地方修改代码,通常是有安全隐患的。通常我们会记得在析构函数里用delete释放指针成员变量,但未必每次都记得到赋值运算符函数来添加代码释放内存。

更好的办法在复制运算符函数中利用析构函数自动释放实例已有的内存。下面是这种思路的参考代码:

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;
}

在这个函数中,我们定义一个临时实例strTemp,并把strTemp的m_pData指向当前实例(*this)的m_pData。由于strTemp是个局部变量,但程序员运行到if的外面是也就出了的该变量的域,就会自动调用strTemp的析构函数,就会把strTemp.m_pData所指向的内存释放掉。由于strTemp.m_pData指向的内存就是当前实例之前m_pData的内存。这就相当于自动调用析构函数释放当前实例的内存。如果新增加指针成员变量,我们只需要在析构函数里正确地释放,而不需要对赋值运算符函数做任何修改。

本文已经收录到《剑指Offer——名企面试官精讲典型编程题》一书中,有改动,书中的分析讲解更加详细。欢迎关注。

博主何海涛对本博客文章享有版权。网络转载请注明出处http://zhedahht.blog.163.com/。整理出版物请和作者联系。

程序员面试题精选100题(30)-赋值运算符重载函数[C/C++/C#]相关推荐

  1. 程序员面试题精选100题

    程序员面试题精选100题(01)-把二元查找树转变成排序的双向链表 题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表.要求不能创建任何新的结点,只调整指针的指向. 比如将二元查找树   ...

  2. [程序员面试题精选100题]13.第一个只出现一次的字符

    [题目] 在一个字符串中找到第一个只出现一次的字符.如输入abaccdeff,则输出b. [分析] [代码] /********************************* * 日期:2013- ...

  3. 程序员面试题精选100题(51)-顺时针打印矩阵

    // 程序员面试题精选100题(51)-顺时针打印矩阵.cpp : 定义控制台应用程序的入口点. //#include "stdafx.h" #include <iostre ...

  4. 程序员面试题精选100题:求从1到n的正数中1出现的次数

    // 程序员面试题精选100题(25):求从1到n的正数中1出现的次数 // 如 f(253) = (2!=0) * 100 + 2 * f(99) + (5!=0) * 10 + 5 * f(9) ...

  5. 程序员面试题精选100题:41-50解题报告

    程序员面试题精选100题(41)-把数组排成最小的数[算法]   题目:输入一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的一个.例如输入数组{32,  321},则输出这两个能 ...

  6. 程序员面试题精选100题:11-40解题报告

    程序员面试题精选100题(11)-求二元查找树的镜像[数据结构]   题目:输入一颗二元查找树,将该树转换为它的镜像,即在转换后的二元查找树中,左子树的结点都大于右子树的结点.用递归和循环两种方法完成 ...

  7. [程序员面试题精选100题]19.反转链表

    题目 输入一个链表的头结点,反转该链表,并返回反转后链表的头结点. 分析 假设经过若干操作,我们已经把结点 pre之前的指针调整完毕,这些结点的next指针都指向前面一个结点.现在我们遍历到结点cur ...

  8. 程序员面试题精选100题(03)-子数组的最大和[算法]

    题目:输入一个整形数组,数组里有正数也有负数.数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和.求所有子数组的和的最大值.要求时间复杂度为O(n). 例如输入的数组为1, -2, 3, ...

  9. python程序员面试题精选100题_在Python程序员面试中被问的最多的10道题

    我们在为大家整Python程序员面试试题中,发现了一些被面试官问到的最多的一些问题,以下就是本篇内容: Python是个非常受欢迎的编程语言,随着近些年机器学习.云计算等技术的发展,Python的职位 ...

最新文章

  1. mgr在mysql中指是什么字段_MySQL MGR
  2. php获取longtext字段为空,php – 在longtext字段上准备好的mysqli select语句将返回空...
  3. 杨元庆:乐Pad更适合中国消费者
  4. brew 安装java8_mac使用brew安装Java8
  5. C#异常--System.IO.FileLoadException:“混合模式程序集是针对“v2.0.50727”版的运行时生成的错误...
  6. 写在2021: 值得关注/学习的前端框架和工具库
  7. mysql中的派生表
  8. python学习--交互式图形编程实例四
  9. cuSPARSE库:(十一)cusparseCreateSolveAnalysisInfo()
  10. markdown html图片,Markdown语法对应的HTML标签实现
  11. Ghost for linux 工具备份还原系统
  12. 三星java3倍拍照手机_最强安卓拍照手机!三星Note 8将采用双摄+三倍光学变焦
  13. Intelli IDEA快捷键(配合IdeaVim)
  14. Running pip as root will break packages and permissions. You should install packages reliably by usi
  15. linux谷歌浏览器无法登陆,新版CentOS 7.1上的谷歌浏览器无法启动
  16. [心得]如何系统自学经济学
  17. Linux-CentOS上的服务搭建
  18. 如何在 Unity 中制作一个道具系统
  19. 硬件版--苹果ios免越狱脚本实现硬件方案
  20. 特网云服务器 WindowsServer2012 关闭IE增强机制

热门文章

  1. JVM-01Java内存区域与内存溢出异常(上)【运行时区域数据】
  2. Linux-find命令
  3. Dubbo和SpringCloud的区别
  4. python 计算算术平方根
  5. Java设计模式中的六大设计原则
  6. php权限二进制,PHP_二进制交叉权限微型php类分享,靓点:1、多对多交叉场景分配 - phpStudy...
  7. 手机碎屏怎么导出里面的数据_Flyme数据抢救功能,手机碎屏后的最后倔强
  8. linux内核加载卡主,请教mx6,linux3.0.35,tf卡能启动uboot但是无法加载内核问题
  9. signature=0e42fe6b348b65f88748ba8ecefece12,Low power BIST
  10. c语言中常见的变量,C语言中的变量详解