面试题1:赋值运算符函数

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

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

分析

我们知道,C++ 中类的 6 个默认的函数分别是构造,拷贝构造,析构,赋值运算符的重载,取址运算符的重载和它的常量版本。其中前 4 个在面试中最常问到。比如在继承/组合类中构造和析构函数的调用顺序,派生类中析构函数是否应该设置为 virtual,拷贝构造在何时被调用以及注意事项等等。

但要注意的是,对于拷贝构造函数和赋值运算符的重载函数,C++ 默认实现的是按「位」拷贝的方式,也就是将该对象的内存原封不动地挪到新对象的内存中。所以对于成员变量中含有指针的类,我们一定需要自己实现这两个方法(除非你就打算以默认的方式实现),否则在析构时会将同一块空间释放两次导致崩溃。这就是「深浅拷贝」问题。

解决方案有两种:重新分配内存并拷贝或实现引用计数。很明显,对于 CMyString 类我们需要采用前者。

答案代码如下:

CMyString& CMyString::operator=(const CMyString& str)
{
    delete []m_pData;
    m_pData=NULL;
    size_t len=strlen(str.m_pData);
    m_pData=new char[len+1];
    memcpy(m_pData,str.m_pData,len+1);
    return *this;
}
CMyString& CMyString::operator=(const CMyString& str)
{
    if(&str!=this)
    {
        delete []m_pData;
        m_pData=NULL;
        size_t len=strlen(str.m_pData);
        m_pData=new char[len+1];
        memcpy(m_pData,str.m_pData,len+1);
    }
    return *this;
}
CMyString& CMyString::operator=(const CMyString& str)
{
    CMyString tmp(str.m_pData);
    std::swap(tmp.m_pData,m_pData);
    return *this;
}
CMyString& CMyString::operator=(CMyString str)
{
    swap(str.m_pData,m_pData);
    return *this;
}

【完】

如果你有任何想法或是可以改进的地方,欢迎和我交流!

完整代码及测试用例在 github 上:点我前往