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

题目

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

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

解析

首先,要思考一下类中已经声明的函数如何实现,当然这个过程可能没必要写出来。类CMyString内部使用char *存储信息,C语言中常用的几个字符串处理函数要熟悉,比如strlen()strcpy()

CMyString::CMyString(char * pData) {
    // 函数的默认参数实现时不需要标明
    if(pData == NULL) {
        m_pData = new char[1];
        m_pData[0] = '\0';
    } else {
        m_pData = new char[strlen(pData) + 1];
        strcpy(m_pData, pData);
    }
}
CMyString::CMyString(const CMyString & str) {
    m_pData = new char[strlen(str.m_pData) + 1];
    strcpy(m_pData, str.m_pData);
}
CMyString::~CMyString() {
    delete [] m_pData;
}

解决这个问题需要关注一下几点:

  • 赋值函数的返回值类型应声明为该类型的引用,从而允许连续赋值。
  • 形参应声明为常量引用,提高代码效率。
  • 赋值前释放实例自身已有的空间,避免内存泄露。
  • 操作前判断传入的参数和当前的实例是否为同一实例。

解法1:经典解法,未考虑内存不足导致new char抛出异常。

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

上面的代码考虑的问题已经很周到了,但是却没注意到内存不足导致new char抛出异常,此时程序很容易崩溃。也就是说一旦在赋值运算符函数内部抛出一个异常,CMyString的实例不再保持有效的状态,这就违背了异常安全性原则。

解法2:考虑异常安全性,分配内容成功后再释放原来的内容。

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

解法3:先创建一个临时实例,再交换临时实例和原来的实例。

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;
}

上面的解法中,如果内存不足抛出异常,依然能够保证实例的状态还是有效的。

为了检验赋值效果,顺便写了几个测试函数,主要测试了普通赋值、连续赋值、赋值给自己等点。

void CMyString::print() {
    printf("%s\n", m_pData);
}
void test1() {
    // 普通赋值
    printf("test1\n");
    CMyString str1("hello, world.");
    CMyString str2;
    str2 = str1;
    str1.print();  // hello, world.
    str2.print();  // hello, world.
}
void test2() {
    // 连续赋值
    printf("test2\n");
    CMyString str1("hello, world.");
    CMyString str2, str3;
    str3 = str2 = str1;
    str3.print();  // hello, world.
}
void test3() {
    // 赋值给自己
    printf("test3\n");
    CMyString str("hello, world.");
    str = str;
    str.print();  // hello, world.
}

小结

该题主要考察了C++的基础语法、内存泄露、异常安全性等问题,看似简单但考虑周到确实有一定难度的。

参考

  • 剑指Offer——名企面试官精讲典型编程题 - 何海涛

(全文完)

转载于:https://my.oschina.net/sintune/blog/384989

你可能感兴趣的:(赋值运算符函数 - 面试题1)