题目:如下为类型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;
}