3.异常安全的赋值运算符重载

一、题目

  如下为类型CMyString,请为该类型添加赋值运算符函数。

 1 class CMyString
 2 {
 3 public:
 4     CMyString(char* pData)
 5     {
 6         m_pData = new char[strlen(pData) + 1];
 7         strcpy(m_pData, pData);
 8     }
 9
10     CMyString(): m_pData(NULL) {}
11
12
13     CMyString(const CMyString& str);
14
15     ~CMyString()
16     {
17         delete []m_pData;
18     }
19
20     CMyString& operator =(const CMyString& str);
21
22     void Print() const
23     {
24         printf("%s\n", m_pData);
25     }
26
27
28 private:
29     char* m_pData;
30 };

二、经典解法

  经典解法代码实现如下:

 1 CMyString& CMyString::operator =(const CMyString &str)
 2 {
 3     // 自身赋值
 4     if (this == &str)
 5         return *this;
 6
 7
 8     m_pData = new char[strlen(str.m_pData) + 1]; // 加一,为存放字符串的结束符‘\0‘
 9     strcpy(m_pData, str.m_pData);
10
11     return *this;
12 }

  这是一个经典的解法,为了防止自身赋值,先判断复制对象,是否是自身,如果是,则什么都不做。这个方法可以应对常规的情况。但是,其没有考虑异常安全。在这里的

new char[],可能会由于内存不足导致其抛出异常。

三、考虑异常安全的解法

  实现代码如下:

 1 CMyString& CMyString::operator =(const CMyString &str)
 2 {
 3     if (this != &str)
 4     {
 5         CMyString strTemp(str);
 6
 7         char* pTemp = strTemp.m_pData;
 8         strTemp.m_pData = m_pData;
 9         m_pData = pTemp;
10     }
11
12     return *this;
13 }

  在该赋值函数中,如果判断不是自身赋值,那么先用拷贝构造函数以str构造一个临时对象strTemp,此时对于char的内存分配转移到临时对象的拷贝构造函数中,如果抛出异常,那么对于该实例本身来说,没有任何改变,不影响该实例本身的使用。如果临时对象没有出异常,那么将实例自身的m_pData和strTemp.m_pData交换,由于strTemp是临时对象,在作用域结束时,自动调用析构函数,释放内存,而此时的strTemp的m_pData已经指向了原实例的m_pData的内存。这样就能自动释放内存了。同时也是异常安全的。

  

时间: 2024-10-17 10:24:08

3.异常安全的赋值运算符重载的相关文章

C++异常安全的赋值运算符重载 【微软面试100题 第五十五题】

题目要求: 类CMyString的声明如下: class CMyString { public: CMyString(char *pData=NULL); CMyString(const CMyString &str); ~CMyString(void); CMyString &operator=(const CMyString &str); private: char *m_pData; }; 请实现其赋值运算符的重载函数,要求异常安全,即当对一个对象进行赋值时发生异常,对象的状

拷贝构造函数与赋值运算符重载函数要点

拷贝构造函数 一个小例子 最近在<剑指Offer>上看到了一道题(程序如下),要求我们分析编译运行的结果,并提供3个选项: A. 编译错误: B. 编译成功,运行时程序崩溃:C. 编译运行正常,输出10. 1 #include <iostream> 2 using namespace std; 3 4 class A 5 { 6 private: 7 int value; 8 9 public: 10 A(int n) { value = n; } 11 A(A other) {

第五篇:明确拒绝不想编译器自动生成的拷贝构造函数和赋值运算符重载函数

前言 如果你不想要编译器帮你自动生成的拷贝机制 (参考前文),那么你应当明确的拒绝. 如何拒绝?这便是本文要解决的主要问题. 问题描述 当你定义了一个类,而这个类中各对象之间也是封装的 - 禁止同类对象之间的相互赋值以及复制,那么你需要屏蔽掉编译器帮你生成的拷贝构造函数以及赋值运算符. 在许多代码中,会看到通过将拷贝构造函数和赋值运算符重载函数声明为私有且不予实现来实现这个功能.然而,这不是最科学的做法. 因为这没有做到真正的屏蔽:你在自己的成员函数中,或者友元函数中仍然可以调用这两个私有函数,

明确拒绝不想编译器自动生成的拷贝构造函数和赋值运算符重载函数

前言 如果你不想要编译器帮你自动生成的拷贝机制 (参考前文),那么你应当明确的拒绝. 如何拒绝?这便是本文要解决的主要问题. 问题描述 当你定义了一个类,而这个类中各对象之间也是封装的 - 禁止同类对象之间的相互赋值以及复制,那么你需要屏蔽掉编译器帮你生成的拷贝构造函数以及赋值运算符. 在许多代码中,会看到通过将拷贝构造函数和赋值运算符重载函数声明为私有且不予实现来实现这个功能.然而,这不是最科学的做法. 因为这没有做到真正的屏蔽:你在自己的成员函数中,或者友元函数中仍然可以调用这两个私有函数,

拷贝构造函数和赋值运算符重载的区别

拷贝构造函数是用一个已存在的对象去构造一个不存在的对象(拷贝构造函数毕竟还是构造函数嘛),也就是初始化一个对象.而赋值运算符重载函数是用一个存在的对象去给另一个已存在并初始化过(即已经过构造函数的初始化了)的对象进行赋值. 它们定义上的区别,楼上的已经说过了. 比如:String s1("hello"),s2=s1;//拷贝构造函数Sring s1("hello"),s2;s1=s2;//赋值运算符重载以下情况都会调用拷贝构造函数:1.一个对象以值传递的方式传入函数

赋值运算符重载

对于非内部类对象的赋值,会存在一个默认的赋值运算符重载函数. 如下面的代码中,c2=c1这句中调用了类A的默认的赋值运算符重载函数,实现了c2.real=c1.real;  c2.image=c1.image; class A{ private: int real; int image; public: A(int r,int i) { real=r; image=i; } }; int main() { A c1(1,2); A c2(0,0); c2=c1; } 那么赋值运算符重载函数 显式

C++ Primer 学习笔记_27_操作符重载与转换(2)--++/--运算符重载、!运算符重载、赋值运算符重载 、String类([]、 +、 += 运算符重载)、&gt;&gt;和&lt;&lt;运算符重载

C++ Primer 学习笔记_27_操作符重载与转换(2)--++/--运算符重载.!运算符重载.赋值运算符重载 .String类([]. +. += 运算符重载).>>和<<运算符重载 一.++/--运算符重载 1.前置++运算符重载 成员函数的方式重载,原型为: 函数类型 & operator++(); 友元函数的方式重载,原型为: friend 函数类型 & operator++(类类型 &); 2.后置++运算符重载 成员函数的方式重载,原型为:

赋值运算符重载和拷贝构造函数 AND 浅拷贝与深拷贝

赋值运算符重载: 是用一个已经存在的对象去给另一个已经存在并初始化(调用过构造函数)的对象进行赋值. 拷贝构造函数:其实本质还是构造函数,用一个已存在的对象去构造一个原先不存在的对象. string a("hello"); string b("world"); string c =a ;   //拷贝构造函数 c = b;           //调用赋值函数 一般来说是在数据成员包含指针对象的时候,应付两种不同的处理需求的 一种是复制指针对象,一种是引用指针对象

C++ String类 ( 构造、拷贝构造、赋值运算符重载和析构函数)

class String { public: //普通构造函数 String(const char *str = NULL) { if(str == NULL) { m_data = new char[1]; *m_data = '\0'; } else { m_data = new char[strlen(str) + 1]; strcpy(m_data, str); } } //拷贝构造函数 String(const String &s) { m_data = new char[strlen