剑指Offer算法实现之一:赋值运算符函数

来源:互联网 发布:nba中国官方软件 编辑:程序博客网 时间:2024/06/01 23:52

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

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

思路:考虑下列问题:
  1. 返回自身的引用
  2. 处理“自我赋值”
  3. 异常安全性
编译环境:ArchLinux+Clang3.3, X86_64
实现一:
    现在临时字符数组上作拷贝,然后与对象的数据成员交换,最后将多余的数组释放。关键代码如下:
CMyString& CMyString::operator=(const CMyString& oth){    if (this == &oth) return *this; // 此句即使略去,自我赋值也不会带来错误,自我复制几率极小,因此不会带来性能问题    char *tmp = new char[strlen(oth.m_pData)+1]; // 创建临时字符数组    strcpy(tmp, oth.m_pData);    swap(m_pData, tmp); // 交换指针,标准库函数    delete[] tmp; // 释放原对象的数据    return *this;}

实现二:
    使用copy-swap技术,解决实现一代码冗余的问题。这样,实现一中临时对象释放问题就可交由CMyString的析构对象负责,并且可充分利用copy构造函数。关键代码如下:
CMyString& CMyString::operator=(const CMyString& oth){    CMyString strTmp{oth}; // copy    swap(this->m_pData, strTmp.m_pData); // swap(标准库函数)    return *this;}

实现三:
   实现二提高了代码复用。也可以使用C++11的move操作符函数和右值引用达到同样的效果。尽管多提供了一个move操作符函数,但对于CMyString这样持有潜在大量动态内存的类来说,不仅可以供编译器优化,而且还可手动调用,这是值得的。
CMyString& CMyString::operator=(CMyString&& oth){    swap(this->m_pData, oth.m_pData); //做了一个swap,this持有的动态内存由oth的析构函数释放    return *this;}CMyString& CMyString::operator=(const CMyString& oth){    CMyString strTmp{oth};    *this = move(strTmp); // 右值引用语义    return *this;}
完整代码:
#include <iostream>#include <cstring>using namespace std;class CMyString{public:    CMyString(const char *pData = nullptr);    CMyString(const CMyString& str);    CMyString& operator=(const CMyString& oth);    CMyString& operator=(CMyString&& oth);    ~CMyString();    friend ostream& operator<<(ostream& out, CMyString& str);private:    char *m_pData;};CMyString::CMyString(const char *pData){    if (pData == nullptr){        m_pData = nullptr;        return;    }    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(){    if (m_pData != nullptr) {        delete[] m_pData;    }}ostream& operator<<(ostream& out, CMyString& str){    return out << str.m_pData;}/* * 实现一CMyString& CMyString::operator=(const CMyString& oth){    if (this == &oth) return *this; // 此句即使略去,自我赋值也不会带来问题    char *tmp = new char[strlen(oth.m_pData)+1];    strcpy(tmp, oth.m_pData);    swap(m_pData, tmp);    delete[] tmp;    return *this;}*//* 实现二CMyString& CMyString::operator=(const CMyString& oth){    CMyString strTmp{oth};    swap(this->m_pData, strTmp.m_pData);    return *this;}*//* 实现三 */CMyString& CMyString::operator=(CMyString&& oth){    swap(this->m_pData, oth.m_pData);    return *this;}CMyString& CMyString::operator=(const CMyString& oth){    CMyString strTmp{oth};    *this = move(strTmp);    return *this;}// 测试驱动int main(){    CMyString s{"hello"};    CMyString t;    cout << (t = s) << endl;}