【剑指offer】一、赋值运算符函数

题目:

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

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

题目解析:

1、拿到一个题目时,我们应该先理清大概的思路,不要着急直接写代码。思考可能会发生的一些场景,怎样处理这些场景。以及考虑到一些极端情况。

2、赋值运算符函数的注意事项:

  • 是否把返回值的类型声明为该类型的引用,并在函数结束前返回该类型的引用(即*this)。只有返回一个引用,才会允许连续赋值。
  • 是否把传入的参数类型声明为常量引用。如果传入的参数不是引用而是实例的话,就得再调用一次复制构造函数,降低了代码的效率。
  • 是否释放实例自己已有的内存。如果没有在分配新内存之前释放原有内存,就会造成内存泄漏。
  • 是否判断传入的参数与当前的实例是不是同一个实例。

普通解法:
CMyString& CMyString::operator=(const CMyString& str){
    if (this != &str){
        //释放原有内存
        delete[] m_pData;
        m_pData = NULL;
        //分配新内存
        m_pData = new char(strlen(str.m_pData) + 1);
        strcpy(m_pData, str.m_pData);
    }
    return *this;
}

这是普通的解法,上面所说的赋值运算符函数的注意事项,我们也都符合要求。但是我们还是要想想一些极端情况这个函数能处理吗?比如在这个函数里我们是先释放内存,再分配新内存。可是如果在释放了当前对象的原有内存后,给当前内存分配新内存时因为内存不足而失败,抛出异常而退出时。这时问题就来了,当前对象的原有空间释放掉了,新空间也申请失败,当前对象的指针变成了一个野指针,这时代码就出问题了,程序会崩溃。那我们要如何改进呢?这时我们可以借助临时变量来实现,也就是我们升级版的函数。


考虑异常安全性的解法:

我们可以先创建一个临时实例,在交换临时实例和原来的实例。因为该临时实例是一个局部变量,所以在出了作用域之后,系统会自动调用该类的析构函数,释放临时变量所指向的空间。代码如下:

CMyString& CMyString::operator=(const CMyString& str){
    if (this != &str){
        //创建临时变量
        CMyString Temp(str);
        char* pTemp = Temp.m_pData;
        Temp.m_pData = m_pData;
        m_pData = pTemp;
    }
    return *this;
}

浅析浅拷贝,深拷贝及写时拷贝(copy_on_write),模拟实现String类。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值