String类的一个简单实现
class CMyString
{
friend ostream &operator<<(ostream &o, const CMyString &str);
public:
CMyString(const char *str);
~CMyString();
CMyString(const CMyString &other);
CMyString &operator=(const CMyString &str);
private:
char *m_pData;
};
CMyString::CMyString(const char *str)
{
if (!str){
m_pData = new char[1];
if (m_pData){
m_pData[0] = '\0';
}
}
m_pData = new char[strlen(str)+1];
if (m_pData){
strcpy(m_pData, str);
}
}
CMyString::CMyString(const CMyString &other)
{
m_pData = new char[strlen(other.m_pData)+1];
if (m_pData){
strcpy(m_pData, other.m_pData);
}
}
CMyString::~CMyString()
{
delete []m_pData;
m_pData = NULL;
}
/*
应用RAII思想,tempStr在离开作用域后自动调用析构函数释放原字符串中m_pData部分。
*/
CMyString &CMyString::operator=(const CMyString &other)
{
if (this == &other)
return *this;
CMyString tempStr(other);
char *pTemp = tempStr.m_pData;
tempStr.m_pData = m_pData;
m_pData = pTemp;
return *this;
}
ostream &operator<<(ostream &o, const CMyString &str)
{
o << str.m_pData;
return o;
}
要点:
- 赋值运算符中需返回实例自身的引用,保证允许连续赋值。
- 复制构造函数参数需声明为常量引用,否则调用时会导致栈溢出。
- 赋值运算符中参数建议声明为常量引用,可以少调用一次复制构造函数。
- 分配新的内存之前需释放自身已有的空间。
- 赋值运算符中需要判断传入参数和实例是否是同一个实例(自赋值)。
- 考虑异常安全性,new char时内存不足时m_pData是空指针,容易导致程序崩溃。建议应用RAII思想,如赋值运算符中将资源的分配控制转移到复制构造函数中进行。