C++::实现String类的浅拷贝形式
(由于工程量较小,就不分文件了)
/*
*本代码版权归高小调博客所有
*作者:最近头比较大,不知道怎么有效学习C++的高小调
*日期:2016-10-20
*代码功能:String类的浅拷贝形式
*/
#include<iostream>
class String{
public:
//构造函数,默认初始化为空串
String(const char *pStr = ""){
//防止String s(NULL);
if(NULL != pStr){
//pStr不为空时,开辟一段内存,并将源字符串拷贝过去
_pStr = new char[strlen(pStr)+1];
strcpy(_pStr,pStr);
}else{
//pStr为空时,开辟两个字节,创建空串
//(多申请一个字节,方便析构的时候直接调用delete[]释放内存)
_pStr = new char[1];
*_pStr = '\0';
}
}
~String(){
delete[] _pStr;
_pStr = NULL;
}
private:
char *_pStr;
};
int main(){
String s1("Hello");
String s2(s1);
return 0;
}
这样的程序,只要你敢运行,它就敢崩溃!
为什么我写这个String类会崩溃?我们来分析一下:
在这个String类中,因为没有显式的定义拷贝构造函数,因此编译器会默认合成一个.
而编译器默认合成的拷贝构造函数,只是做简单地做赋值操作,把被拷贝对象内的各个成员,一一原封不动的赋值给了新对象的各个成员.
因此,拷贝构造函数调用完成之后,s1的pStr指针与s2的pStr指针,指向同一块内存区域.而这种以值拷贝的形式,我们称之为浅拷贝.
程序运行至此,一切正常,不足以崩溃.
而再接着向下走的时候,当mian函数内代码执行完之后,s1、s2对象即将被销毁,因此要调用析构函数.
因为栈"先入后出"的特性,决定了首先调用的是s2的析构函数,当s2析构函数调用完成之后,pStr指针所指向的内存就会被释放.
程序运行至此,也一切正常,不足以崩溃.
当程序继续接着向下走,析构s1对象时,因为s1的pStr指向的内存与s2的pStr指向的内存区域相同,而s2已经释放过了这块区域,因此当s1的析构函数再次调用delete[]尝试释放pStr指针所指向的内存区域时,异常发生了,程序崩溃了!
说了这么多,那么问题来了:C++中的String类到底该怎么写?
浙公网安备 33010602011771号