• C++ 浅拷贝和深拷贝


    拷贝构造函数默认的是浅拷贝。当不涉及到堆内存时用浅拷贝完全可以,否则就需要深拷贝了。

    浅拷贝相当于一个箱子有多个钥匙,但其中一个人打开箱子取走箱子里的东西时,其他人是不知道的。

    深拷贝是有多个箱子每个箱子对应一个钥匙,但一个人取走他的钥匙对应的箱子里的东西时,不会对其他人产生影响。

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 class A{
     6 public:
     7     A() {
     8         cnt1++;
     9         name = new char(20);
    10         strcpy(name, "hello");
    11         cout << "A" << name << endl;
    12     }
    13     ~A() {
    14         cnt2++;
    15         cout << "~A" << name << endl;
    16         delete name;
    17         name = nullptr;
    18     }
    19     char *name;
    20     static int cnt1;
    21     static int cnt2;
    22 };
    23 
    24 int A::cnt1 = 0;
    25 int A::cnt2 = 0;
    26 int main() {
    27 
    28     {
    29         A a;
    30         A b(a);
    31     }
    32 
    33     cout << A::cnt1 << ' ' << A::cnt2 << endl;
    34     return 0;
    35 }

    运行结果如下:

    很明显对象b的name是一个空指针了,如果对空指针进行操作的话就会出现问题了。

    所以涉及到堆内存时就需要自己实现拷贝构造函数了。

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 class A{
     6 public:
     7     A() {
     8         cnt1++;
     9         name = new char(20);
    10         memmove(name, "hello", strlen("hello"));
    11         cout << "A" << name << endl;
    12     }
    13     A(const A&b) {
    14         name = new char(strlen(b.name)+1);
    15         memmove(name, b.name, strlen(b.name));
    16     }
    17     ~A() {
    18         cnt2++;
    19         cout << "~A" << name << endl;
    20         delete name;
    21         name = nullptr;
    22     }
    23     char *name;
    24     static int cnt1;
    25     static int cnt2;
    26 };
    27 
    28 int A::cnt1 = 0;
    29 int A::cnt2 = 0;
    30 int main() {
    31 
    32     {
    33         A a;
    34         A b(a);
    35     }
    36 
    37     return 0;
    38 }

    运行结果如下:

    随便讨论下vector。

    vector可以看成一个可变大小的数组,有两个属性size和capacity,分别是大小和容量。大小表示当前元素的数量,而容量是表示当前能容量的元素数量。

    当push_back()时,如果size和capacity相同时,首先向内存申请capacity*2(这个基数一般在1.5~2.0之间)大小的内存。然后将当前的元素拷贝到新的内存中,在释放原来的内存。

    这样如果vector的类型没有自己实现拷贝构造函数时,默认是浅拷贝,比如下面这样就会出现问题。

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 class A{
     6 public:
     7     A() {
     8         cnt1++;
     9         name = new char(20);
    10         strcpy(name, "hello");
    11         cout << "A" << name << endl;
    12     }
    13     ~A() {
    14         cnt2++;
    15         cout << "~A" << name << endl;
    16         delete name;
    17         name = nullptr;
    18     }
    19     char *name;
    20     static int cnt1;
    21     static int cnt2;
    22 };
    23 
    24 int A::cnt1 = 0;
    25 int A::cnt2 = 0;
    26 int main() {
    27     {
    28         vector<A> vs;
    29         for(int i = 0; i < 4; i ++) {
    30             A a;
    31             vs.push_back(a);
    32             cout <<"size:"<< vs.size() << ' ' <<  vs.capacity() << endl << endl;
    33         }
    34     }
    35     cout << A::cnt1 << ' ' << A::cnt2 << endl;
    36     return 0;
    37 }

    结果如下:

    明显出现了问题,就如提示所言,产生了两次释放。

    如果自己实现了拷贝构造函数就不同了。

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 class A{
     6 public:
     7     A() {
     8         cnt1++;
     9         name = new char(20);
    10         strcpy(name, "hello");
    11         cout << "A" << name << endl;
    12     }
    13     A(const A&b) {
    14         name = new char(strlen(b.name)+1);
    15         strcpy(name, b.name);
    16     }
    17     ~A() {
    18         cnt2++;
    19         cout << "~A" << name << endl;
    20         delete name;
    21         name = nullptr;
    22     }
    23     char *name;
    24     static int cnt1;
    25     static int cnt2;
    26 };
    27 
    28 int A::cnt1 = 0;
    29 int A::cnt2 = 0;
    30 int main() {
    31     {
    32         vector<A> vs;
    33         for(int i = 0; i < 4; i ++) {
    34             A a;
    35             vs.push_back(a);
    36             cout <<"size:"<< vs.size() << ' ' <<  vs.capacity() << endl << endl;
    37         }
    38     }
    39     cout << A::cnt1 << ' ' << A::cnt2 << endl;
    40     return 0;
    41 }

    运行结果如下:

  • 相关阅读:
    常见cout格式输出
    P3332 [ZJOI2013]K大数查询
    pdb
    OS
    ubuntu su failure when password was right
    【opencv安裝】ubuntu16 opencv安装+测试
    shell脚本读取文件+读取命令行参数+读取标准输入+变量赋值+输出到文件
    xshell上传下载文件
    【sed / awk脚本编写】
    shell正则式解析身份证和手机号
  • 原文地址:https://www.cnblogs.com/xingkongyihao/p/10841582.html
Copyright © 2020-2023  润新知