C++——深拷贝&浅拷贝

C++定义一个类,如果什么方法都不写,默认会自动生成4个方法:构造函数、拷贝构造函数、赋值语句、析构函数。

大多数人只知道这四个,实际上还有2个,对一般对象的取地址,对常对象的取地址

 1 #include<iostream>
 2 using namespace std;
 3 class Test {
 4 public:
 5     Test(int d = 0) :data(d)
 6     {
 7         cout << "Create Test Object:" << this << endl;
 8     }
 9     Test(const Test &t)
10     {
11         cout << "Copy Create Test Object:" << this << endl;
12         this->data = t.data;
13     }
14     Test& operator=(const Test &t)
15     {
16         cout << "Assign:" << this << "=" << &t << endl;
17         if (this != &t)
18         {
19             this->data = t.data;
20         }
21         return *this;
22     }
23     Test* operator&()
24     {
25         return this;
26     }
27     const Test* operator&()const
28     {
29         return this;
30     }
31     ~Test()
32     {
33         cout << "Free Test Object:" << this << endl;
34     }
35 private:
36     int data;
37 };
38 
39 int main(int argc, char **argv)
40 {
41     Test t;
42     Test t1 = t;
43     Test t2;
44     t2 = t1;
45 
46     Test t3;
47     Test *pt = &t3;
48 
49     const Test t4;
50     const Test *pt1 = &t4;
51     return 0;
52 }
View Code

如果构造函数内部开辟了内存空间,则需要在析构函数中释放内存。当使用对象初始化对象时,C++默认是浅拷贝,即只是指针只想相同内存。当其中的一个对象被析构,活着的对象还只想被释放的内存,然后当他死亡时再次释放内存,导致内存被释放多次,程序崩溃。

这段代码,变异不报错,但是运行时崩溃

 1 #include<iostream>
 2 using namespace std;
 3 
 4 class String
 5 {
 6 public:
 7     String(const char *str = "")
 8     {
 9         if (*str == '\0')
10         {
11             data = (char *)malloc(sizeof(char));
12             data[0] = '\0';
13         }
14         else
15         {
16             data = (char *)malloc(sizeof(char)*(strlen(str) + 1));
17             strcpy(data, str);
18         }
19     }
20     ~String()
21     {
22         free(data);
23         data = NULL;
24     }
25 private:
26     char *data;
27 };
28 
29 int main(int argc, char **argv)
30 {
31     const char *str = "Hello";
32     String s1(str);
33     String s2(s1);
34 }
View Code

改进代码,自己指定拷贝构造函数(深拷贝)

 1 #include<iostream>
 2 using namespace std;
 3 
 4 class String
 5 {
 6 public:
 7     String(const char *str = "")
 8     {
 9         if (*str == '\0')
10         {
11             data = (char *)malloc(sizeof(char));
12             data[0] = '\0';
13         }
14         else
15         {
16             data = (char *)malloc(sizeof(char)*(strlen(str) + 1));
17             strcpy(data, str);
18         }
19     }
20     String(const String &s)
21     {
22         data= (char *)malloc(sizeof(char)*(strlen(s.data) + 1));
23         strcpy(data, s.data);
24     }
25     ~String()
26     {
27         free(data);
28         data = NULL;
29     }
30 private:
31     char *data;
32 };
33 
34 int main(int argc, char **argv)
35 {
36     const char *str = "Hello";
37     String s1(str);
38     String s2(s1);
39 }
View Code

同样,对于赋值函数也需要深拷贝。浅拷贝方式导致程序崩溃原因同上。增加赋值函数后代码

 1 #include<iostream>
 2 using namespace std;
 3 
 4 class String
 5 {
 6 public:
 7     String(const char *str = "")
 8     {
 9         if (*str == '\0')
10         {
11             data = (char *)malloc(sizeof(char));
12             data[0] = '\0';
13         }
14         else
15         {
16             data = (char *)malloc(sizeof(char)*(strlen(str) + 1));
17             strcpy(data, str);
18         }
19     }
20     String(const String &s)
21     {
22         data= (char *)malloc(sizeof(char)*(strlen(s.data) + 1));
23         strcpy(data, s.data);
24     }
25     String& operator=(const String &s)
26     {
27         if (this != &s)
28         {
29             data = (char *)malloc(sizeof(char)*(strlen(s.data) + 1));
30             strcpy(data, s.data);
31         }
32         return *this;
33     }
34     ~String()
35     {
36         free(data);
37         data = NULL;
38     }
39 private:
40     char *data;
41 };
42 
43 int main(int argc, char **argv)
44 {
45     const char *str = "Hello";
46     String s1(str);
47     String s2(s1);
48     String s3;
49     s3 = s1;
50 }
View Code

但是这段代码有内存泄露风险。如果String s3("World"); s3 = s1;就会内存泄漏。“World”字符串对应的内存泄漏,改进代码

 1 #include<iostream>
 2 using namespace std;
 3 
 4 class String
 5 {
 6 public:
 7     String(const char *str = "")
 8     {
 9         if (*str == '\0')
10         {
11             data = (char *)malloc(sizeof(char));
12             data[0] = '\0';
13         }
14         else
15         {
16             data = (char *)malloc(sizeof(char)*(strlen(str) + 1));
17             strcpy(data, str);
18         }
19     }
20     String(const String &s)
21     {
22         data= (char *)malloc(sizeof(char)*(strlen(s.data) + 1));
23         strcpy(data, s.data);
24     }
25     String& operator=(const String &s)
26     {
27         if (this != &s)
28         {
29             free(data);
30             data = NULL;
31             data = (char *)malloc(sizeof(char)*(strlen(s.data) + 1));
32             strcpy(data, s.data);
33         }
34         return *this;
35     }
36     ~String()
37     {
38         free(data);
39         data = NULL;
40     }
41 private:
42     char *data;
43 };
44 
45 int main(int argc, char **argv)
46 {
47     const char *str = "Hello";
48     String s1(str);
49     String s2(s1);
50     String s3("World");
51     s3 = s1;
52 }
View Code

一般赋值语句的流程是:

1、是不是给自己赋值

2、释放原有空间

3、申请空间进行拷贝赋值

4、返回自身对象

如果一个类里面,他的数据成员包含指针,我们需要重新编写拷贝构造、赋值语句。这两个函数默认的会提供指针的浅拷贝,浅赋值

猜你喜欢

转载自www.cnblogs.com/kelamoyujuzhen/p/9443484.html