你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

C++——拷贝构造函数的浅copy和深copy

[复制链接]
gaosmile 发布时间:2020-8-31 23:43

一、深拷贝和浅拷贝构造函数总结:

1、两个特殊的构造函数:

(1)无参构造函数:

没有参数的构造函数

Class Test
{
public:
     Test()
     {
       //这是一个无参构造函数
     }
};

当类中没有定义构造函数时,编译器默认提供一个无参构造函数,并且其函数体为空;换句话来说,就是我们在类中,不用我们程序猿自己写,编译就自动提供了无参构造函数(只是我们肉眼看不到!)

#include <iostream>
#include <string>

class Test{

//编译器默认给我们提供了一个无参构造函数,只是我们肉眼看不到

};



int main()
{
   Test t;

  return 0;
}

结果输出(编译时能够通过的):

root@txp-virtual-machine:/home/txp# g++ test.cpp
root@txp-virtual-machine:/home/txp#


(2)拷贝构造函数:

参数为const class_name&的构造函数

class Test{
public:
   Test(const Test& p)
   {
      
   
   }
}

当类中没有定义拷贝构造函数时,编译器默认提供了一个拷贝构造函数,简单的进行成员变量的值赋值

#include <iostream>
#include <string>

class Test{

private:
   int i;
   int j;
public:
/*  Test(const Test& p)编译器默认提供这样操作的
   {
      i = p.i;
      j = p.j;
   }*/


};



int main()
{
   Test t;



  return 0;
}

输出结果(编译可以通过):

root@txp-virtual-machine:/home/txp# g++ test.cpp
root@txp-virtual-machine:/home/txp#

(3)注意:

在写程序的时候,定义的类对象初始化时看属于哪种类型的:

Test t;//对应无参构造函数

Test t(1);//对应有参构造函数

Test t1;
Test t2=t1;//对应拷贝构造函数

比如下面我定义的类对象属于无参构造函数(当然前提是你手写了其他构造函数,虽然说编译器会默认提供,但是既然要手写,那么三种构造函数就在定义类对象的时候按需求来写),如果只写了有参数构造函数,那么编译器就会报错:

#include <iostream>
#include <string>

class Test{

private:
   int i;
   int j;
public:
  Test(int a)
  {
     i = 9;
     j=8;
  }
  Test(const Test& p)
   {
      i = p.i;
      j = p.j;
   }


};
int main()
{
   Test t;
  return 0;
}


输出结果:

root@txp-virtual-machine:/home/txp# g++ test.cpp
test.cpp: In function ‘int main()’:
test.cpp:25:9: error: no matching function for call to ‘Test::Test()’
    Test t;
         ^
test.cpp:25:9: note: candidates are:
test.cpp:15:3: note: Test::Test(const Test&)
   Test(const Test& p)
   ^
test.cpp:15:3: note:   candidate expects 1 argument, 0 provided
test.cpp:10:3: note: Test::Test(int)
   Test(int a)
   ^
test.cpp:10:3: note:   candidate expects 1 argument, 0 provided

4、拷贝构造函数的意义:

(1)浅拷贝

拷贝后对象的物理状态相同

(2)深拷贝

拷贝后对象的逻辑状态相同

(3)编译器提供的拷贝构造函数只进行浅拷贝

代码版本一:

#include <stdio.h>
#include <string>

class Test{
private:
   int i;
   int j;
   int *p;
public:
   int getI()
   {
      return i;
   }
   int getJ()
   {
      return j;
   }
   int *getP()
   {
      return p;
   }
   Test(int a)
   {
      i = 2;
      j = 3;
      p = new int;
      *p = a;
  }
  void free()
  {

    delete p;
  }
};
int main()
{
   Test t1(3);//Test t1 3;
   Test t2 = t1;

  printf("t1.i = %d, t1.j = %d, t1.p = %p\n", t1.getI(), t1.getJ(), t1.getP());
  printf("t2.i = %d, t2.j = %d, t2.p = %p\n", t2.getI(), t2.getJ(), t2.getP());

   t1.free();
   t2.free();
   
   return 0;
}

输出结果:

root@txp-virtual-machine:/home/txp# g++ test.cpp
root@txp-virtual-machine:/home/txp# ./a.out
t1.i = 2, t1.j = 3, t1.p = 0x1528010
t2.i = 2, t2.j = 3, t2.p = 0x1528010
*** Error in `./a.out': double free or corruption (fasttop): 0x0000000001528010 ***
Aborted (core dumped)

注解:出现了段错误,仔细分析,我们发现这里释放了堆空间两次(因为我们这里没有调用拷贝构造函数,也就是自己去写拷贝构造函数;所以这种情况是浅拷贝,不能释放两次堆空间):

微信图片_20200831234255.png

代码版本二(加上拷贝构造函数):

#include <stdio.h>
#include <string>

class Test{
private:
   int i;
   int j;
   int *p;
public:
   int getI()
   {
      return i;
   }
   int getJ()
   {
      return j;
   }
   int *getP()
   {
      return p;
   }
   Test(int a)
   {
      i = 2;
      j = 3;
      p = new int;
      *p = a;
  }
  Test(const Test& t)
  {
    i = t.i;
    j = t.j;
    p = new int;

    *p = *t.p;
  }

  void free()
  {

    delete p;
  }
};
int main()
{
   Test t1(4);
   Test t2 = t1;

   printf("t1.i = %d, t1.j = %d, t1.p = %p\n", t1.getI(), t1.getJ(), t1.getP());
   printf("t2.i = %d, t2.j = %d, t2.p = %p\n", t2.getI(), t2.getJ(), t2.getP());
   t1.free();
   t2.free();

   return 0;
}

输出结果:

root@txp-virtual-machine:/home/txp# g++ test.cpp
root@txp-virtual-machine:/home/txp# ./a.out
t1.i = 2, t1.j = 3, t1.p = 0xb0a010
t2.i = 2, t2.j = 3, t2.p = 0xb0a030

注解:从打印的p地址空间来看,就知释放的两个对象的堆空间不同,不再是指向同一堆空间了;同时我们发现浅拷贝只是简单数值上的进行赋值而已;深拷贝不只是简单的值赋值,而是从内存的角度来看,是操作不同的内存。

5、什么时候需要进行深拷贝?

(1)对象中有成员指代了系统中的资源

  • 成员指向了动态内存空间

  • 成员打开了外存中的文件

  • 成员使用了系统中的网络端口


注意:一般来说,自定义拷贝构造函数(也就是我们自己手写的),必然需要实现深拷贝!

二、总结:

  • C++编译器会默认提供构造函数

  • 无参构造函数用于定义对象的默认初始化状态

  • 拷贝构造函数在创建对象时拷贝对象的状态

  • 对象的拷贝有浅拷贝和深拷贝两种方式。


好了,今天的分享就到这里,如果文章中有错误或者不理解的地方,可以交流互动,一起进步。


收藏 评论0 发布时间:2020-8-31 23:43

举报

0个回答

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版