当前位置: 首页 > news >正文

C++之《剑指offer》学习记录(4):赋值运算符函数

笔者最近在找工作时,无意间读到了一本名为《剑指offer》的书,粗略翻阅了一下,感觉这将会是一本能让我不再苦恼于笔试和面试“手搓代码”的书。故笔者写下该系列博客记录自己的学习历程,希望能和这本书的读者朋友们一起交流学习心得。
介绍:《剑指Offer:名企面试官精讲典型编程题(第2版)》剖析了80个典型的编程面试题,系统整理基础知识、代码质量、解题思路、优化效率和综合能力这5个面试要点。
编程题链接:牛客网在线编程_算法面试_面试必刷TOP101 (nowcoder.com)
本博客关键词:赋值运算符函数

由于笔者在读这本书之前没有听说过“赋值运算符函数”,所以第一次看有点没搞懂这个函数是什么意思,后来查阅了资料配合理解代码,才知道原来“赋值运算符函数”其实就是类中重载=运算符的函数。该函数的写法:ClassName& operator=(const ClassName& other);

题设

有如下类的声明,请为该类添加赋值运算符函数。(相比于书中的声明,这里我做了一些小修改。)

class MyClass
{
private:char *m_pData;public:MyClass(const char *pData = nullptr); // 构造函数MyClass(const MyClass &other); // 拷贝构造函数~MyClass(); // 析构函数
};

常规写法

如果我们只是写算法题,关注该函数本身即可,如果是在整个测试用例中写该函数,需要在类中声明,如下:

class MyClass
{
private:char *m_pData;public:MyClass(const char *pData = nullptr);MyClass(const MyClass &other);~MyClass();MyClass &operator=(const MyClass &other); // 赋值运算符函数
};

赋值运算符函数常规(初级)写法

MyClass &MyClass::operator=(const MyClass &other)
{if (this == &other){return *this;}delete[] m_pData;m_pData = nullptr;m_pData = new char[strlen(other.m_pData) + 1];strcpy(m_pData, other.m_pData);return *this;
}
  1. 输入参数为什么是常量引用?首先使用const声明对象只读,保证了在赋值运算的过程中函数不会对原对象进行修改,保证了安全性;其次使用&表示输入为引用类型,避免了按值传参时对拷贝构造函数的调用,减少了调用开销,可以提高代码效率。
  2. 为什么函数返回类型是引用?函数返回引用,才能保证连续赋值(如a=b=c),如果返回类型是void,则不能实现连续赋值的功能。在类中this表示指向指向当前对象的指针,所以*this得到的就是当前对象的实例。
  3. 函数开头对赋值对象进行判断,如果是自赋值this==&other),则直接返回。
  4. 如果不是自赋值,则在分配新内存之前delete释放实例自身已有的内存避免出现内存泄漏

高级写法

相较于常规写法,高级写法实现了赋值运算符函数中的异常安全性。代码如下:

MyClass &MyClass::operator=(const MyClass &other)
{if (this != &other){MyClass Temp(other);  // 调用拷贝构造函数char *tempPtr = Temp.m_pData;Temp.m_pData = m_pData;m_pData = tempPtr;}return *this;
}
  1. 高级写法与常规写法相同的地方是都会对自赋值情况进行判断
  2. 高级写法的主要高级之处在于,该写法通过创建临时实例,并通过一个临时变量交换临时实例与当前实例的目标值(m_pData),从而实现对当前实例进行赋值的同时还释放了实例自身原有的内存,避免了内存泄漏。在这个写法中,如果因为内存不足抛出了异常,但代码中并没有修改原来实例的状态,因此该实例的状态仍然是有效的。
  3. 该段代码在if判断语句里调用了拷贝构造函数,创建了一个临时实例,通过中间变量tempPtr让临时实例指向当前实例的m_pData,让当前实例指向临时实例的m_pData,由于临时实例来自于拷贝构造,所以此时临时实例的m_pData就是当前实例的目标m_pData。
  4. 由于该拷贝构造函数是在if判读语句里调用的,其生命周期就在这里if语句里,当if语句退出时,临时实例会自动调用析构函数释放内存,这是析构函数释放的内存实际上就是当前实例的m_pData指向的内存!

测试用例

#include <iostream>
#include <cstring>using namespace std;class MyClass
{
private:char *m_pData;public:MyClass(const char *pData = nullptr);MyClass(const MyClass &other);~MyClass();MyClass &operator=(const MyClass &other);void getData(){cout << m_pData << endl;}
};MyClass::MyClass(const char *pData)
{m_pData = new char[strlen(pData) + 1];strcpy(m_pData, pData);cout << "构造函数被调用" << endl;
}MyClass::MyClass(const MyClass &other)
{// 深拷贝m_pData = new char[strlen(other.m_pData) + 1];strcpy(m_pData, other.m_pData);cout << "拷贝构造函数被调用" << endl;
}// 普通写法
// MyClass &MyClass::operator=(const MyClass &other)
// {
//     if (this == &other)
//     {
//         cout << "赋值运算符函数被调用" << endl;
//         return *this;
//     }//     delete[] m_pData;
//     m_pData = nullptr;//     m_pData = new char[strlen(other.m_pData) + 1];
//     strcpy(m_pData, other.m_pData);
//     cout << "赋值运算符函数被调用" << endl;
//     return *this;
// }// 高级写法,实现了异常安全性
MyClass &MyClass::operator=(const MyClass &other)
{if (this != &other){MyClass Temp(other);char *tempPtr = Temp.m_pData;Temp.m_pData = m_pData;m_pData = tempPtr;}return *this;
}MyClass::~MyClass()
{delete[] m_pData;cout << "析构函数被调用" << endl;
}int main(int argc, char const *argv[])
{MyClass a("Tony");MyClass b("Amy");MyClass c(a);a.getData();b.getData();c.getData();c = c = b = a;a.getData();b.getData();c.getData();return 0;
}

http://www.mrgr.cn/news/51247.html

相关文章:

  • 视频分割软件哪个好?无损分割视频片段就靠它
  • 某电子元器件企业人力资源管理体系搭建咨询项目
  • 【观点】机器学习与神经网络荣膺诺贝尔物理学奖的启示:科技的未来与物理学的转变
  • 【你也能从零基础学会网站开发】SQL Server 2000中的bit数据类型
  • leetcode.3194.最小元素和最大元素的最小平均值
  • huggingface的数据集下载(linux下clone)
  • DSOL源码基本函数列表
  • 毕业32年,重回32中
  • 电流检测布局和故障排除指南
  • 【JavaEE】——TCP应答报文机制,超时重传机制
  • Find My门禁卡|苹果Find My技术与门禁卡结合,智能防丢,全球定位
  • 【Python爬虫实战】高效解析和操作XML/HTML的实用指南
  • 云开发 | 如何往云数据库中添加一条新数据
  • 开源OpenStack
  • 【学术论文投稿】Java入门:零基础小白也能轻松掌握的全攻略
  • 免费送源码:Java+B/S+MySQL 多元化智能选课系统的设计与实现 计算机毕业设计原创定制
  • 长上下文 LLMs 兴起,RAG 会成为历史吗?
  • 信息安全领域,对等实体认证服务和访问控制服务的区别
  • 利用Spring Boot构建大创项目资源规划平台
  • 第三课:python学习之安装pygame