系列文章(二):从内存的角度看-----拷贝构造函数(深浅拷贝)

  5 class Test{
  6 public:
  7     Test(int n, const char* ch){
  8         m_ = n;
  9         ch_ = new char[strlen(ch)+1];
 10         strcpy(ch_, ch);
 11     }
 12     ~Test(){
 13         cout << "~Test" << endl;
 14         if(ch_ != NULL){
 15             delete[] ch_;
 16             ch_ = NULL;
 17
 18         }
 19     }
 20     char* get_addr()const{
 21         return ch_;
 22     }
 23
 24 private:
 25     int m_;
 26     char* ch_;
 27 };
 28 int main()
 29 {
 30     Test t1(3, "good");
 31     Test t2 = t1;
 32     printf("t1 = %p\n", t1.get_addr());
 33     printf("t2 = %p\n", t2.get_addr());

 37     return 0;
 38 }
 39

我们以上面的代码为例,当我们调用拷贝构造函数时,如果没有显示的给出拷贝构造函数,则调用默认的拷贝构造函数,而默认的拷贝构造函数是进行浅拷贝的,仅仅简单的完成值的复制。画个图表示以下:
在这里插入图片描述
可以看到对象t2仅仅对t1进行了简单的值的复制,ch_指向同一个内存区域,这样会有严重的后果,那就是会对同一个地址进行多次释放,产生段错。
在这里插入图片描述
总的来说,如果类的成员变量都在栈上进行分配,那么浅拷贝也是可以满足要求的,但如果是堆上的数据,则会多次发生析构行为。

那我要如何解决这个问题那??那就要进行深拷贝,手工编写拷贝构造函数,并在拷贝构造函数中新申请一块内存,并将值复制过来,将指针指向新开辟的内存区域。画个图示意以下:
在这里插入图片描述
修改后的代码如下:

 #include <iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 using namespace std;
  5 class Test{
  6 public:
  7     Test(int n, const char* ch){
  8         m_ = n;
  9         ch_ = new char[strlen(ch)+1];
 10         strcpy(ch_, ch);
 11     }
 12     Test(const Test& another){
 13         m_ = another.m_;
 14         ch_ = new char[strlen(another.ch_)+1];
 15         strcpy(ch_, another.ch_);
 16
 17
 18     }
 19     ~Test(){
 20         cout << "~Test" << endl;
 21         if(ch_ != NULL){
 22             delete[] ch_;
 23             ch_ = NULL;
 24
 25         }
 26     }
 27     char* get_addr()const{
 28         return ch_;
 29     }
 30
 31 private:
 32     int m_;
 33     char* ch_;
 34 };
 35 int main()
 36 {
 37     Test t1(3, "good");
 38     Test t2 = t1;
 39     printf("t1 = %p\n", t1.get_addr());
 40     printf("t2 = %p\n", t2.get_addr());
 41

运行结果:
可以看到两个指针指向的内存地址不同。
在这里插入图片描述

ps:在vscode下并不会出现这个错误,不知道为啥??要大佬指点以下码??

补充有关匿名对象的有趣现象

匿名对象啥时候会出现?

Test go(){
    Test en;
    return en;
}

这种情况下会返回一个匿名对象,同时会调用匿名对象的拷贝构造函数。
比较有趣的是到底该匿名对象什么时候会析构???

  • 如果用匿名对象来初始化另一个同类型的对象A,匿名对象被转化为有名对象A,被扶正了,只会在该对象A被销毁时调用一次析构函数。
  • 如果用匿名对象赋值给另一个同类型的对象B,匿名对象立刻被析构,而对象B在销毁时调用一次析构函数。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值