1 题目

如下为类型 CMystring 的声明,请为该类型添加赋值运算符函数。

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

2 题解

这道题就是一道重载赋值运算符为成员函数的题。需要考虑以下几点:

  • 是否把返回值的类型声明为该类型的引用(CMystring& ...),并在函数结束后返回实例的引用(*this)。只有返回一个,才可以连续赋值。否则,如果返回值是void,将不能连续赋值。
  • 是否把传入的参数的类型声明为常量引用(const CMystring &str)。如果传入的不是引用而是实例,那么从形参到实参会调用一次复制构造函数。把参数声明为引用可以避免这样的无谓消耗,提高效率。同时,我们在函数内不会修改传入的实例的状态,因此应该加上const关键字。
  • 是否释放实例自身已有的内存。若未在分配空间前释放自身已有的空间,将会造成内存泄漏。
  • 判断传入的参数和当前的实例(*this)是不是同一个实例。如果是,则不赋值。如果不判断,在释放自身内存时,也会删除原有的内存,就再也找不到赋值的内容。

2.1 经典解法,初级程序员

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

注意:

这样做乍一看很不错,但是在分配内存之前先用 delete 释放了实例 m_pData 的内存。此时,若内存不足导致new char 抛出异常,则 m_pData 就是一个空指针,容易导致程序崩溃,也丢失了我们自身原来的内容。

要想解决这个问题,有两个办法:

  1. new 分配新内容,再delete 释放已有内容。这样及时分配内存失败,亦可以保留原先的实例不会被修改。
  2. 更好的办法是用赋值的实例创建一个临时实例,再交换临时实例和原来的实例。

2.2 高级解法,考虑异常安全性

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 是一个局部变量,当程序运行到if 的外面时,也就出了改变量的作用域,就会自动调用 strTemp 的析构函数, 释放掉原有的内存。

同时我们在 CMystring 的构造函数里用 new 分配内存。若内存不足抛出诸如 bad_alloc 异常,但我们还没有修改原来实例的状态,这也就保证了异常安全性。

3 完整代码

#define _CRT_SECURE_NO_WARNINGS  // 否则报不安全,VS2015#include <cstdio>
#include <cstring>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;
}
*/// 高级做法 A = B
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;
}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 expected 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");
}int main(int argc, char* argv[])
{Test1();Test2();Test3();return 0;
}

剑指offer (01):赋值运算符函数 (C++ 实现)相关推荐

  1. 剑指Offer #01 二维数组中的查找(Java描述)

    题目来源:牛客网-剑指Offer专题 题目地址:二维数组中的查找 题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一 ...

  2. 《剑指offer》Partition函数及其Partition函数周边

      Partion函数最早出现于快速排序算法,但其代表的分治思想,在<剑指offer>这本书中求数组中位数(面试题39,数组中出现次数超过一半的数字)中也有所涉及,将其汇总在一起,称之为P ...

  3. python剑指offer 包含min函数的栈

    题目描述 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1)). # -*- coding:utf-8 -*- class Solution:def _ ...

  4. 剑指Offer 包含min函数的栈

    时间限制:1秒 空间限制:32768K 热度指数:158697 本题知识点: 栈 算法知识视频讲解 题目描述 定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数. 给出代码: cla ...

  5. 剑指offer 包含min函数的栈

    题目描述 定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数. 先介绍一下java.util.Stack.peek()方法实例: 下面的例子显示java.util.Stack.pee ...

  6. 剑指offer——01二维数组中的查找.

    class Solution {public:bool Find(int target, vector<vector<int> > array) {int m =array.s ...

  7. 剑指offer.01 数组中重复的数(0504刷题自用)

    代码 class Solution {public:int findRepeatNumber(vector<int>& nums) {unordered_map <int,i ...

  8. 《剑指offer》写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。...

    弱菜刷题还是刷中文题好了,没必要和英文过不去,现在的重点是基本代码能力的恢复. [题目] 剑指offer 写一个函数,求两个整数之和,要求在函数体内不得使用+.-.*./四则运算符号. [思路] 直觉 ...

  9. 赋值运算符函数__from 剑指Offer

    前段时间忙于项目,难得偷得几日闲,为即将到来的就业季做准备.在面试时,应聘者要注意多和考官交流,只有具备良好的沟通能力,才能充分了解面试官的需求,从而有针对性地选择算法解决问题. 题目来源于<剑 ...

最新文章

  1. 2020阿里全球数学大赛:3万名高手、4道题、2天2夜未交卷,73人天团,正式出道!
  2. oracle 默认表空间 10g,Oracle10g 表空间管理
  3. 认知AI的兴起:2025年AI将会发生质的飞跃
  4. 【死磕Java并发】-----Java内存模型之happens-before
  5. jqgrid的动态下拉框实现,并解决不能获取值的问题
  6. WebBrowser1.Navigate重复载入同一页面时载入的是旧页面
  7. sublime text 3 中的php代码语法检测
  8. XML配置文件中的Spring配置文件
  9. android:图片裁剪
  10. 【Tyvj】1473校门外的树3 线段树/树状数组 区间修改+单点访问
  11. 宅男福利!20行Python代码,一网打尽B站小姐姐的直播信号源!
  12. 黑客入侵效果网页html,满屏绿字滑下效果
  13. 计算机配置里面没有网络选项,win7网络共享中心里面的更改适配器设置里面没有无线网络连接...-win7适配器没有无线网络连接,win7网络适配器未...
  14. table 手机 滑动_移动端touch事件滚动
  15. 【懒懒的Python学习笔记九】
  16. WPA3也不安全啦?WPA3-R3 H2E了解一下
  17. 基于android的手机掌上购物
  18. 解决:FTP隔离用户ftp将数据发送到服务器之前不加密或编码,要保护密码和数据数据,请用WEB文件夹(WenDAV)
  19. Python find()方法
  20. 计算机科学与技术在国内外的形势,计算机科学与技术就业形势分析

热门文章

  1. linux怎么返回上级目录啊,用cd/命令却这样:bash:cd/:没有那个文件或目录
  2. 框架选择的原因及其说明
  3. 解决Gradle DSL method not found: ‘android()’
  4. LinuxMint下的Orionode源码安装
  5. 分享一个同行的blog,UI方面的。
  6. [原]正则表达式模式匹配入门
  7. 黑马程序员---java基础-Java之GUI
  8. hdu 3879 Base Station 最大权闭合图
  9. 聊聊spring的ioc
  10. OpenERP 关于页码总页数