鱼C论坛

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

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

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

class MyClass
{
public:
        MyClass(int *p);
        MyClass(const MyClass &rhs);
        ~MyClass();

        MyClass & operator = (const MyClass &rhs);
        void print();
private:
        int *ptr;
};

MyClass::MyClass(int *p)
{
        std::cout << "进入主构造器\n";
        ptr = p;
        std::cout << "离开主构造器\n";
}

MyClass::MyClass(const MyClass &rhs)
{
        std::cout << "进入副本构造器\n";
        *this = rhs;
        std::cout << "离开副本构造器\n";
}
MyClass::~MyClass()
{
        delete ptr;
}


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

                ptr = new int;
                *ptr = *(rhs.ptr);
        }

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

void MyClass::print()
{
        std::cout << *ptr <<"\n";
}

int main()
{
        MyClass obj3(new int(3));
        MyClass obj4 = obj3;
        obj3.print();
        obj4.print();

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

ptr = new int;
*ptr = *(rhs.ptr);
}

std::cout << "离开赋值语句重载\n";
return *this;
}
各位请帮帮忙啊~


最佳答案

查看完整内容

你的 MyClass obj4 = obj3;这句话说明obj4里面的int*ptr没有申请过内存,那么当你delete ptr的时候肯定就要报错啰。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2014-12-30 16:11:43 | 显示全部楼层
你的 MyClass obj4 = obj3;这句话说明obj4里面的int*ptr没有申请过内存,那么当你delete ptr的时候肯定就要报错啰。
想知道小甲鱼最近在做啥?请访问 -> 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)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

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

                ptr = new int;
                *ptr = *(rhs.ptr);
        }

        std::cout << "离开赋值语句重载\n";
        return *this;
}
这里指针已经不是指向同一个内存了,属于深拷贝。
但是我发现,将“delete ptr;”删掉就没有问题了。那么是不是可以解释成:在拷贝前,并没有生成obj4这个内存,但是却对其进行了删除,导致出错。我这样的解释对吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

恩恩,的确是这样的,看来源码就是有点问题,十分谢谢您。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

你的程序根本没有使用到赋值运算符
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2015-1-4 10:58:06 | 显示全部楼层
MyClass obj4 = obj3;
这里调用的是拷贝构造函数而不是赋值运算符。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2015-1-9 11:52:59 | 显示全部楼层
仰望天上的光 发表于 2015-1-4 10:58
MyClass obj4 = obj3;
这里调用的是拷贝构造函数而不是赋值运算符。
MyClass::MyClass(const MyClass &rhs)
{
        std::cout << "进入副本构造器\n";
        *this = rhs;
        std::cout << "离开副本构造器\n";
}
副本构造器里面有调用吧?
MyClass obj4 = obj3;首先进入副本构造器,然后调用重载的“=”运算符,不是这样吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

我运行了一下,没错啊
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

小甲鱼也没错。。。。就是在我这有错,哎,算了,这个问题。但其实理论上是有错的,需要改的~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-11-25 14:26

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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