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类到底该怎么写?