Eden00 发表于 2023-4-20 21:27:06

C++ 堆区类析构报错

本帖最后由 Eden00 于 2023-4-20 22:45 编辑

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



如下代码,没有报错,但是每次运行到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;
}

isdkz 发表于 2023-4-20 21:27:07

Eden00 发表于 2023-4-20 22:32


经过我重新审查代码,找到了问题所在。问题出在析构函数的调用顺序。首先,`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;
    }
}


现在,您的程序应该能够正常运行,不会报错。

isdkz 发表于 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;
    }
}


这样修改后,您的程序应该不会再报错,并按预期运行。

Eden00 发表于 2023-4-20 22:31:30

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

改了之后还是不行

Eden00 发表于 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;
}

Eden00 发表于 2023-4-21 10:02:27

isdkz 发表于 2023-4-20 23:38
经过我重新审查代码,找到了问题所在。问题出在析构函数的调用顺序。首先,`Computer`的析构函数被调用, ...

c0是CPU指针,v0是videocard指针按照定义应该不能调用supplier类的函数。
但是思路是对的,应该要确保supplier析构时,父类们也一起析构,因此感谢啦
页: [1]
查看完整版本: C++ 堆区类析构报错