鱼C论坛

 找回密码
 立即注册
查看: 1941|回复: 9

副本构造器(源自小甲鱼的C++快速入门)

[复制链接]
发表于 2014-12-30 16:11:42 | 显示全部楼层 |阅读模式
2鱼币
在小甲鱼的C++快速入门当中,[36]副本构造器那一课。为了避免“逐个复制”的问题,使用重构“=”赋值还有自己定义副本构造器的方法。仿造小甲鱼代码如下:

  1. #include <iostream>

  2. class MyClass
  3. {
  4. public:
  5.         MyClass(int *p);
  6.         MyClass(const MyClass &rhs);
  7.         ~MyClass();

  8.         MyClass & operator = (const MyClass &rhs);
  9.         void print();
  10. private:
  11.         int *ptr;
  12. };

  13. MyClass::MyClass(int *p)
  14. {
  15.         std::cout << "进入主构造器\n";
  16.         ptr = p;
  17.         std::cout << "离开主构造器\n";
  18. }

  19. MyClass::MyClass(const MyClass &rhs)
  20. {
  21.         std::cout << "进入副本构造器\n";
  22.         *this = rhs;
  23.         std::cout << "离开副本构造器\n";
  24. }
  25. MyClass::~MyClass()
  26. {
  27.         delete ptr;
  28. }


  29. MyClass & MyClass::operator = (const MyClass &rhs)
  30. {
  31.         std::cout << "进入赋值语句重载\n";
  32.         if(this != &rhs)
  33.         {
  34.                 delete ptr;                //必须先删除之前的内存

  35.                 ptr = new int;
  36.                 *ptr = *(rhs.ptr);
  37.         }

  38.         std::cout << "离开赋值语句重载\n";
  39.         return *this;
  40. }

  41. void MyClass::print()
  42. {
  43.         std::cout << *ptr <<"\n";
  44. }

  45. int main()
  46. {
  47.         MyClass obj3(new int(3));
  48.         MyClass obj4 = obj3;
  49.         obj3.print();
  50.         obj4.print();

  51.         std::cin.get();
  52.         return 0;
  53. }
复制代码

应该是没有问题的,但是运行总是出错,出错语句:
  1. MyClass & MyClass::operator = (const MyClass &rhs)
  2. {
  3. std::cout << "进入赋值语句重载\n";
  4. if(this != &rhs)
  5. {
  6. delete ptr;   //总是在此处出错

  7. ptr = new int;
  8. *ptr = *(rhs.ptr);
  9. }

  10. std::cout << "离开赋值语句重载\n";
  11. return *this;
  12. }
复制代码
各位请帮帮忙啊~


最佳答案

查看完整内容

你的 MyClass obj4 = obj3;这句话说明obj4里面的int*ptr没有申请过内存,那么当你delete ptr的时候肯定就要报错啰。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2014-12-30 16:11:43 | 显示全部楼层
你的 MyClass obj4 = obj3;这句话说明obj4里面的int*ptr没有申请过内存,那么当你delete ptr的时候肯定就要报错啰。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2015-1-3 13:10:03 | 显示全部楼层
MyClass obj3(new int(3));
这句使得obj3.ptr指向动态分配出来的空间(为方便描述,称之为空间A)
MyClass obj4 = obj3;
这句使得obj4.ptr也指向空间A

obj4对象消亡的时候会释放空间A。
obj3对象消亡的时候企图再次释放空间A,所以报错

本质原因是副本构造函数写得有问题,应该使用深拷贝而非浅拷贝(若看不懂“深拷贝”和“浅拷贝”请自行baidu)
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2015-1-3 21:12:20 | 显示全部楼层
仰望天上的光 发表于 2015-1-3 13:10
MyClass obj3(new int(3));
这句使得obj3.ptr指向动态分配出来的空间(为方便描述,称之为空间A)
MyClas ...

但是我已经对“=”赋值语句进行了重载,
  1. MyClass & MyClass::operator = (const MyClass &rhs)
  2. {
  3.         std::cout << "进入赋值语句重载\n";
  4.         if(this != &rhs)
  5.         {
  6.                 delete ptr;                //必须先删除之前的内存

  7.                 ptr = new int;
  8.                 *ptr = *(rhs.ptr);
  9.         }

  10.         std::cout << "离开赋值语句重载\n";
  11.         return *this;
  12. }
复制代码

这里指针已经不是指向同一个内存了,属于深拷贝。
但是我发现,将“delete ptr;”删掉就没有问题了。那么是不是可以解释成:在拷贝前,并没有生成obj4这个内存,但是却对其进行了删除,导致出错。我这样的解释对吗?
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2015-1-3 21:16:28 | 显示全部楼层
Xiao_肚oO 发表于 2015-1-2 23:32
你的 MyClass obj4 = obj3;这句话说明obj4里面的int*ptr没有申请过内存,那么当你delete ptr的时候肯定就要 ...

恩恩,的确是这样的,看来源码就是有点问题,十分谢谢您。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2015-1-4 10:57:10 | 显示全部楼层
清风袋袋 发表于 2015-1-3 21:12
但是我已经对“=”赋值语句进行了重载,
这里指针已经不是指向同一个内存了,属于深拷贝。
但是我发现 ...

你的程序根本没有使用到赋值运算符
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2015-1-4 10:58:06 | 显示全部楼层
MyClass obj4 = obj3;
这里调用的是拷贝构造函数而不是赋值运算符。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2015-1-9 11:52:59 | 显示全部楼层
仰望天上的光 发表于 2015-1-4 10:58
MyClass obj4 = obj3;
这里调用的是拷贝构造函数而不是赋值运算符。
  1. MyClass::MyClass(const MyClass &rhs)
  2. {
  3.         std::cout << "进入副本构造器\n";
  4.         *this = rhs;
  5.         std::cout << "离开副本构造器\n";
  6. }
复制代码

副本构造器里面有调用吧?
MyClass obj4 = obj3;首先进入副本构造器,然后调用重载的“=”运算符,不是这样吗?
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2015-1-9 15:18:04 | 显示全部楼层
清风袋袋 发表于 2015-1-9 11:52
副本构造器里面有调用吧?
MyClass obj4 = obj3;首先进入副本构造器,然后调用重载的“=”运算符,不 ...

我运行了一下,没错啊
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2015-1-11 19:40:06 | 显示全部楼层
GRRRARD 发表于 2015-1-9 15:18
我运行了一下,没错啊

小甲鱼也没错。。。。就是在我这有错,哎,算了,这个问题。但其实理论上是有错的,需要改的~
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-7-5 08:49

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表