浅析:浅拷贝 及 深拷贝的传统写法

 浅拷贝会造成指针悬挂的问题。

 举个例子:两个对象是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 }

 

posted @ 2016-04-16 16:38  ProLyn  阅读(922)  评论(0编辑  收藏  举报