String类赋值运算符函数

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

class CMyString
{
public:
    CMyString(char* pdata = NULL);
    CMyString(const CMyString& str);
    //赋值函数
    CMyString& operator=(const CMyString& str); 

    ~CMyString(); 

private:
    char* m_data;
};

面试官考察的点:
1、 是否把返回值的类型声明为该类型的引用,并在函数返回前,返回自身的引用(*this)。只有返回一个引用,才可以允许连续赋值。如果函数的返回值为void,则像str1=str2=str3这样的连续赋值将不会被通过
2、 是否把传入的参数类型声明为常引用。如果传入的参数不是引用而是实=实例的话,那么从形参到实参要进行一次拷贝构造函数的调用,把参数声明为引用,可以避免无谓的消耗,提高效率。同时,在赋值的时候,不应该改变传入参数的状态,所以,应该声明为常引用,加上const关键字
3、 是否释放自身的空间,否则程序将出现内存泄漏
4、 避免自赋值。判断传入的参数是否和当前的实例*this是一个实例,如果是同一个实例,则不进行赋值操作,直接返回。如果事先不进行判断,在释放自身实例的内存的时候就会出现问题,一旦释放了自身的内存,传入的参数的内存也同时释放了,因此再也找不到需要赋值的内容了

//初级程序员解法:

CMyString& CMyString::operator=(const CMyString& str)
{
    //防止自赋值
    if (&str == this)
        return *this;
    //释放自身空间
    delete[] m_data;
    m_data = NULL; 
    //分配空间,赋值
    m_data = new char[strlen(str.m_data)+1]; 
    strcpy(m_data, str.m_data); 

    //返回自身引用
    return *this; 
}

//考虑异常安全的解法,高级程序员必备
在前面的函数中,我们在分配内存之前先delete释放了自身的内存。但是如果此时内存不足,分配内存的时候抛出异常,那么m_data将是一个空指针,很容易导致程序崩溃,违背了异常安全原则
要想在赋值函数中实现异常安全性。有两种方法:1、一个简单的方法是先用new分配新内容,再delete释放已有的内容,这样在分配成功之后再释放原来的内容,也就是当分配失败时可以保证CMyString的实例不会被修改。2、还有一个更好的方法就是创建一个临时对象,再交换临时对象和原来对象

CMyString& CMyString::operator=(const CMyString& str)
{
    if (&str != this)
    {
        //先通过拷贝构造函数创建一个临时对象 
        CMyString strtmp(str);
        //交换临时对象和自身的m_data
        char* pTmp = m_data;
        m_data = strtmp.m_data;
        strtmp.m_data = pTmp; 

    }
    return *this;
}

这个函数中,先创建一个临时对象,然后交换临时对象和实例自身的m_data,由于临时对象是一个局部对象,出了if语句就会自动调用临时对象的析构函数,就会把临时对象所指的那块内存释放掉。
在这个新的代码中,我们在CMyString的构造函数里用new分配内存,如果内存不足抛出异常,这时,我们还没有修改原来实例的状态。就保证了异常安全性

发布了73 篇原创文章 · 获赞 107 · 访问量 21万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章