剑指offer - 赋值运算符函数

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

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

在添加赋值运算符时,应该关注以下几点:

1、把返回值的类型声明为该类型的引用,并在函数结束前返回实例自身的引用,即 *this。 只有返回一个引用,才允许使用连续赋值。否则如果函数的返回值是void, 应用该赋值运算符将不能使用连续赋值,即不能使用 str1 = str2 = str3 形式,其中str1 2 3 是CMyString的对象;


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


3、赋值过程中应该及时释放实例自身已有的内存,如果我们忘记在分配新内存之前释放它自身已有的内存,那么程序将出现内存泄漏;


4、在进行赋值之前务必判断传入的参数和当前实例(*this)是否属于同个实例。如果是同个实例,则不进行赋值操作直接返回。如果不判断便进 行赋值,一旦他们属于同个实例,我们在释放实例本身内存的时候,便会将传入的参数的内存也同时释放,然后再也找不到需要赋值的内容了

C++代码实现:

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

注:上面的代码一般情况下都没什么问题,但是还是有很小的概率导致程序崩溃。在重新为m_pData分配内存之前,我们是释放了实例m_pData的内存,如果此时内存不足导致new char抛出异常,则m_pData将会是一个空指针。因此,要想维持异常安全性,我们可以在释放内存前先分配内存,只有内存分配成功了我们才释放掉原先的。此外,也可以用另外一种更好的办法,就是先创建一个临时实例并将临时实例与原来的实例进行交换。

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与实例自身的m_pData进行交换。因为strTemp是个局部变量,当程序执行完 if 语句后,就会执行strTemp的析构函数, 并将 strTemp.m_pData 所指向的内存释放掉。因为交换后strTemp.m_pData指向的是原先实例m_pData指向的内存,就相当于是调用析构函数释放实例的内存了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值