剑指offer(典型编程题)笔记一

面试题一

题目:为下面的类型添加赋值运算符函数

class CMyString
{
public:
    CMyString(char* pData = nullptr);
    CMyString(const CMyString& str);
    ~CMyString(void);

    CMyString& operator = (const CMyString& str);

    void Print();
private:
    char* m_pData;
};

注意点:

  1. 返回值是否为该类型的引用:函数返回值要返回自身的引用(*this)。只有这样才可以连续赋值。
  2. 传入的参数类型是否为引用:即在传入的参数前面加上const关键字,避免调用复制构造函数,可以提高代码效率。
  3. 是否释放实例本身的内存:若忘记在分配新内存志强忘记释放自身的空间,程序将会出现内存泄漏。
  4. 传入后判断当前实例与传入参数是不是同一个:如果不实现判断,若为同一个,将导致内存释放时全都被释放了。

写出函数

CMyString& CMyString::operator = (const CMyString& str)
{
    if(this == &str) //如果是自己给自己赋值,直接返回自身
        return *this;

    delete []m_pData; //删除原来的值
    m_pData = nullptr; // 确保 m_pData 不再指向任何已删除的内存区域

    m_pData = new char[strlen(str.m_pData) + 1]; //创建比传入实例大小多一的数组
    strcpy(m_pData, str.m_pData);//将数组中的内容拷贝过去

    return *this;
}

进阶版

在上面的函数中,在分配内存之前先释放了m_pData的内存,如果因为内存不足导致new char失败,将很容易导致程序崩溃(虽然现在电脑一般不会内存不足),这违反了异常安全性原则。
我们有两种方法可以实现异常安全性:

  • 先new分配内容,分配成功后再delete释放已有内容。
  • 创建一个临时实例,再交换临时实例和原来的实例。
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;
}

在新的代码中,如果在构造函数中用new分配内存时如果内存不足会抛出异常。

posted @ 2024-03-22 00:20  YJQING  阅读(10)  评论(0)    收藏  举报