浅析:浅拷贝 及 深拷贝的传统写法
浅拷贝会造成指针悬挂的问题。
举个例子:两个对象是s1和s2的指针_str都指向new开辟的同一块空间,如下图,主程序结束时,对象逐个撤销,先撤销对象s2,会调用析构函数释放动态分配的内存;再撤销对象s1时,s1._str所指向的内存空间已经是无法访问了,而s2._str原先指向的那块内存却无法释放,出现了所谓的指针悬挂! 两个对象企图释放同一块内存,从而导致一块内存被释放两次这也是不行的,运行会出错。
1 #include <iostream> 2 using namespace std; 3 4 class String 5 { 6 public: 7 String(char *str) 8 :_str(new char [strlen(str )+1]) 9 { 10 strcpy(_str, str); 11 } 12 String(const String & s) 13 { 14 _str = s._str; 15 } 16 String& operator=(const String & s ) 17 { 18 if (this !=&s) 19 { 20 _str = s._str; 21 } 22 return *this ; 23 } 24 ~String() 25 { 26 delete[] _str; 27 } 28 private: 29 char* _str; 30 }; 31 32 void Test() 33 { 34 String s1("Lynn" ); 35 String s2=s1; 36 } 37 int main() 38 { 39 Test(); 40 system("pause" ); 41 return 0; 42 }
深拷贝 深拷贝解决了指针悬挂的问题,当调用拷贝构造或赋值运算符的重载函数时,程序会生成一份该内存的拷贝,这样每个指针都会指向一块相对独立的空间,撤销对象时调用析构函数,分别释放他们自己的动态分配的内存,相互之间不影响。如下图:
深拷贝
1 /////////////////////////////////////////////////////////////////////////////////////// 2 3 // 写String类的构造函数时一定要注意参数问题 4 // 首先要考虑到构造的对象分有参数和无参数两种情况 5 // 构造对象的时候不能直接赋值,否则一块内存两次释放的话程序会出错 6 // 无参的构造函数不能将_str指针赋值为NULL,因为不能strlen(NULL) 7 // 赋值运算符的重载要考虑到有可能分配内存失败的问题 8 // 当然,记得要给'\0'分配空间哦 9 // By:Lynn-Zhang 10 //////////////////////////*****************//////////////////////////////////////////// 11 12 #include<iostream> 13 using namespace std; 14 15 class String 16 { 17 public: 18 19 String(char * str="") //不能strlen(NULL) 20 :_str(new char [strlen(str ) + 1]) 21 { 22 strcpy(_str, str); 23 } 24 String(const String &s) 25 :_str(new char [strlen(s ._str) + 1]) 26 { 27 strcpy(_str, s._str); 28 } 29 30 //赋值运算符的重载 31 String& operator=(const String& s) 32 { 33 if (this != &s ) 34 { 35 /* //有可能开辟空间失败,但是却破坏了_str的内容 36 delete[] _str; 37 _str = new char[strlen(s._str) + 1]; 38 strcpy(_str, s._str); */ 39 40 char* tmp = new char [strlen(s ._str) + 1]; 41 strcpy(tmp, s._str); 42 delete[] _str; 43 swap(_str, tmp); 44 45 } 46 return *this ; 47 } 48 char* CStr() 49 { 50 return _str; 51 } 52 ~String() 53 { 54 delete[] _str; 55 } 56 private: 57 char* _str; 58 }; 59 60 61 //函数测试 62 void Test() 63 { 64 String s1("aaaaa" ); 65 cout << s1.CStr() << endl; 66 String s2(s1); 67 cout << s2.CStr() << endl; 68 String s3 = s1; 69 s3= s2; 70 cout << s3.CStr() << endl; 71 String s4; 72 // s4 = s1; 73 cout << s4.CStr() << endl; 74 75 } 76 int main() 77 { 78 Test(); 79 system("pause" ); 80 return 0; 81 }