鱼C论坛

 找回密码
 立即注册
查看: 1569|回复: 5

[已解决]C++ 堆区类析构报错

[复制链接]
发表于 2023-4-20 21:27:06 | 显示全部楼层 |阅读模式
5鱼币
本帖最后由 Eden00 于 2023-4-20 22:45 编辑

补充,似乎问题出在继承,改变继承顺序后,就变成delete c0无法析构,是否有什么问题?

Annotation 2023-04-20 223958.png

如下代码,没有报错,但是每次运行到delete v0;(157行)的时候,会报错Exception has occurred.Unknown signal,请问是为啥?
谢谢!
#include <iostream>

#include <string>

#include <cmath>

#include <stdlib.h>

#include <ctime>

using namespace std;

class CPU
{

public:
    string cname;

    virtual void calculate() = 0;
    ~CPU()
    {
        cout << cname << " CPU is destructed" << endl;
    }
};

class VideoCard
{

public:
    string vname;

    virtual void display() = 0;
    ~VideoCard()
    {
        cout << vname << " video card is destructed" << endl;
    }
};

class Memory
{

public:
    string mname;

    virtual void store() = 0;
    ~Memory()
    {
        cout << mname << " memory is destructed" << endl;
    }
};

class Supplier : public CPU, public VideoCard, public Memory
{

    string name;

    void calculate()
    {

        cout << name << " CPU is calculating" << endl;
    }

    void store()
    {

        cout << name << " memory is stoing" << endl;
    }

    void display()
    {

        cout << name << " video card is displaying" << endl;
    }

public:
    Supplier()
    {

        cout << "Supplier is structed without argument" << endl;
    }

    Supplier(string n) : name(n)
    {

        cout << "Supplier is structed with name as " << n << endl;
    }

    string SetName(string n)
    {

        cout << "Supplier name is set by Class Supplier as " << n << endl;

        name = n;

        return name;
    }

    string GetName()
    {

        return name;
    }

    ~Supplier()
    {

        cout << name << " supplier is destructed" << endl;
    }
};

class Computer
{

    CPU *c0;

    VideoCard *v0;

    Memory *m0;

public:
    Computer(Supplier c, Supplier v, Supplier m)
    {

        c0 = new Supplier(c);

        v0 = new Supplier(v);

        m0 = new Supplier(m);

        c0->cname = c.GetName();

        v0->vname = v.GetName();

        m0->mname = m.GetName();

        cout << "This computer is assembled with " << c0->cname << " CPU, " << v0->vname

             << " video card, " << m0->mname << " memory" << endl;
    }

    ~Computer()
    {

      /* if (c0 != NULL)
        {
            cout << c0->cname << endl
                 << c0 << endl;
            delete c0;

            c0 = NULL;
        }*/

        if (v0 != NULL)
        {
            cout << v0->vname << endl
                 << v0 << endl;
            delete v0;

            v0 = NULL;
        }

        if (m0 != NULL)
        {

            delete m0;

            m0 = NULL;
        }
    }

    void work()
    {

        c0->calculate();

        v0->display();

        m0->store();
    }
};

void fun0()
{

    Supplier q0("Qualcom");

    Supplier i0;

    i0.SetName("Intel");

    Supplier a0("AMD");

    Computer c0(q0, i0, a0);

    c0.work();
}

int main()
{

    fun0();

    system("pause");

    return 1;
}
最佳答案
2023-4-20 21:27:07

经过我重新审查代码,找到了问题所在。问题出在析构函数的调用顺序。首先,`Computer`的析构函数被调用,接着调用`Supplier`的析构函数。但是在`Supplier`的析构函数中,由于它继承了`CPU`、`VideoCard`和`Memory`类,所以它们的析构函数也会被调用。因此,在`Computer`的析构函数中,我们需要确保在删除`c0`、`v0`和`m0`之前调用它们的析构函数。

为了解决这个问题,我们可以在`Supplier`类中添加一个名为`cleanUp`的函数,该函数在`Computer`的析构函数中调用,确保调用`CPU`、`VideoCard`和`Memory`的析构函数。

在`Supplier`类中添加`cleanUp`函数:
void cleanUp()
{
    cname.clear();
    vname.clear();
    mname.clear();
}

在`Computer`类的析构函数中调用`cleanUp`函数:
~Computer()
{
    if (c0 != NULL)
    {
        c0->cleanUp();
        delete c0;
        c0 = NULL;
    }

    if (v0 != NULL)
    {
        v0->cleanUp();
        delete v0;
        v0 = NULL;
    }

    if (m0 != NULL)
    {
        m0->cleanUp();
        delete m0;
        m0 = NULL;
    }
}

现在,您的程序应该能够正常运行,不会报错。
Annotation 2023-04-20 223958.png

最佳答案

查看完整内容

经过我重新审查代码,找到了问题所在。问题出在析构函数的调用顺序。首先,`Computer`的析构函数被调用,接着调用`Supplier`的析构函数。但是在`Supplier`的析构函数中,由于它继承了`CPU`、`VideoCard`和`Memory`类,所以它们的析构函数也会被调用。因此,在`Computer`的析构函数中,我们需要确保在删除`c0`、`v0`和`m0`之前调用它们的析构函数。 为了解决这个问题,我们可以在`Supplier`类中添加一个名为`cleanUp`的函数, ...
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-4-20 21:27:07 | 显示全部楼层    本楼为最佳答案   

经过我重新审查代码,找到了问题所在。问题出在析构函数的调用顺序。首先,`Computer`的析构函数被调用,接着调用`Supplier`的析构函数。但是在`Supplier`的析构函数中,由于它继承了`CPU`、`VideoCard`和`Memory`类,所以它们的析构函数也会被调用。因此,在`Computer`的析构函数中,我们需要确保在删除`c0`、`v0`和`m0`之前调用它们的析构函数。

为了解决这个问题,我们可以在`Supplier`类中添加一个名为`cleanUp`的函数,该函数在`Computer`的析构函数中调用,确保调用`CPU`、`VideoCard`和`Memory`的析构函数。

在`Supplier`类中添加`cleanUp`函数:
void cleanUp()
{
    cname.clear();
    vname.clear();
    mname.clear();
}

在`Computer`类的析构函数中调用`cleanUp`函数:
~Computer()
{
    if (c0 != NULL)
    {
        c0->cleanUp();
        delete c0;
        c0 = NULL;
    }

    if (v0 != NULL)
    {
        v0->cleanUp();
        delete v0;
        v0 = NULL;
    }

    if (m0 != NULL)
    {
        m0->cleanUp();
        delete m0;
        m0 = NULL;
    }
}

现在,您的程序应该能够正常运行,不会报错。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-4-20 22:05:03 | 显示全部楼层
根据您提供的代码,问题出在`Computer`类的构造函数中,您试图将已经构造的`Supplier`对象复制给`CPU`、`VideoCard`和`Memory`指针,这将导致析构时多次删除同一对象。为了解决这个问题,您可以将构造函数参数的类型改为指针,并在`main`函数中分配相应的对象。

首先,将`Computer`的构造函数参数类型更改为指针:
class Computer
{

    CPU *c0;

    VideoCard *v0;

    Memory *m0;

public:
    Computer(Supplier *c, Supplier *v, Supplier *m)
    {

        c0 = c;

        v0 = v;

        m0 = m;

        c0->cname = c->GetName();

        v0->vname = v->GetName();

        m0->mname = m->GetName();

        cout << "This computer is assembled with " << c0->cname << " CPU, " << v0->vname

             << " video card, " << m0->mname << " memory" << endl;
    }

    // ...其他成员函数不变
};

接下来,在`main`函数中分配相应的对象并传递指针:
void fun0()
{

    Supplier *q0 = new Supplier("Qualcom");

    Supplier *i0 = new Supplier;

    i0->SetName("Intel");

    Supplier *a0 = new Supplier("AMD");

    Computer c0(q0, i0, a0);

    c0.work();
}

int main()
{

    fun0();

    system("pause");

    return 1;
}

最后,您需要更新`Computer`类的析构函数,以删除这些动态分配的`Supplier`对象。
~Computer()
{

    if (c0 != NULL)
    {
        delete c0;

        c0 = NULL;
    }

    if (v0 != NULL)
    {
        delete v0;

        v0 = NULL;
    }

    if (m0 != NULL)
    {

        delete m0;

        m0 = NULL;
    }
}

这样修改后,您的程序应该不会再报错,并按预期运行。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-4-20 22:31:30 | 显示全部楼层
isdkz 发表于 2023-4-20 22:05
根据您提供的代码,问题出在`Computer`类的构造函数中,您试图将已经构造的`Supplier`对象复制给`CPU`、`Vi ...

改了之后还是不行
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-4-20 22:32:02 | 显示全部楼层
本帖最后由 Eden00 于 2023-4-20 22:44 编辑
isdkz 发表于 2023-4-20 22:05
根据您提供的代码,问题出在`Computer`类的构造函数中,您试图将已经构造的`Supplier`对象复制给`CPU`、`Vi ...

#include <iostream>

#include <string>

#include <cmath>

#include <stdlib.h>

#include <ctime>

using namespace std;

class CPU
{

public:
    string cname;

    virtual void calculate() = 0;
    ~CPU()
    {
        cout << cname << " CPU is destructed" << endl;
    }
};

class VideoCard
{

public:
    string vname;

    virtual void display() = 0;
    ~VideoCard()
    {
        cout << vname << " video card is destructed" << endl;
    }
};

class Memory
{

public:
    string mname;

    virtual void store() = 0;
    ~Memory()
    {
        cout << mname << " memory is destructed" << endl;
    }
};

class Supplier : public CPU, public VideoCard, public Memory
{

    string name;

    void calculate()
    {

        cout << name << " CPU is calculating" << endl;
    }

    void store()
    {

        cout << name << " memory is stoing" << endl;
    }

    void display()
    {

        cout << name << " video card is displaying" << endl;
    }

public:
    Supplier()
    {

        cout << "Supplier is structed without argument" << endl;
    }

    Supplier(string n) : name(n)
    {

        cout << "Supplier is structed with name as " << n << endl;
    }

    string SetName(string n)
    {

        cout << "Supplier name is set by Class Supplier as " << n << endl;

        name = n;

        return name;
    }

    string GetName()
    {

        return name;
    }

    ~Supplier()
    {

        cout << name << " supplier is destructed" << endl;
    }
};

class Computer
{

    CPU *c0;

    VideoCard *v0;

    Memory *m0;

public:
    Computer(Supplier *c, Supplier *v, Supplier *m)
    {

        c0 = c;

        v0 = v;

        m0 = m;

        c0->cname = c->GetName();

        v0->vname = v->GetName();

        m0->mname = m->GetName();

        cout << "This computer is assembled with " << c0->cname << " CPU, " << v0->vname

             << " video card, " << m0->mname << " memory" << endl;
    }

    ~Computer()
    {

       if (c0 != NULL)
        {
            cout << c0->cname << endl
                 << c0 << endl;
            delete c0;

            c0 = NULL;
        }

        if (v0 != NULL)
        {
            cout << v0->vname << endl
                 << v0 << endl;
            delete v0;

            v0 = NULL;
        }

        if (m0 != NULL)
        {

            delete m0;

            m0 = NULL;
        }
    }

    void work()
    {

        c0->calculate();

        v0->display();

        m0->store();
    }
};

void fun0()
{

    Supplier *q0=new Supplier("Qualcom");

    Supplier *i0=new Supplier("Intel");


    Supplier *a0=new Supplier("AMD");

    Computer c0(q0, i0, a0);

    c0.work();
}

int main()
{

    fun0();

    system("pause");

    return 1;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-4-21 10:02:27 | 显示全部楼层
isdkz 发表于 2023-4-20 23:38
经过我重新审查代码,找到了问题所在。问题出在析构函数的调用顺序。首先,`Computer`的析构函数被调用, ...

c0是CPU指针,v0是videocard指针按照定义应该不能调用supplier类的函数。
但是思路是对的,应该要确保supplier析构时,父类们也一起析构,因此感谢啦
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-12-24 21:57

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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