Почему это удаление вызывает дамп ядра?

0

Этот код работает соответствующим образом, если я не использую, а затем удаляю указатель для Output базового класса. Деструктор для Output вызывается и, похоже, работает соответствующим образом. Я что-то упустил?

// multiple inheritance
// Testing overload of muliple inheritance of pure virtual functions.

#include <iostream>
#include <string>

using namespace std;

class Polygon {
  protected:
    int width, height;
  public:
    Polygon (int a, int b) : width(a), height(b) {}
    ~Polygon() = default;
    virtual int area() = 0;
};

class Output {
  private:
    string* myString;

  public:
    Output() {
      myString = nullptr;
    }

    Output(const string& s) {
      myString = new string(s);
    }

    // This seems to work, but ther core dump happens right afterwards.
    ~Output() {
      cout << "delete called with: " << myString << '\n';
      if (myString != nullptr)
        delete myString;
    }
    virtual int area() = 0;
    void print () {
      cout << *myString << this->area() << '\n';
    }
};



class Rectangle: public Polygon, public Output {
  public:
    Rectangle (int a, int b) : Polygon(a,b), Output{"A Rectangle area is: "} {}
    int area () {
     return width*height;
   }
};

class Triangle: public Polygon, public Output  {
  public:
    Triangle (int a, int b) : Polygon{a,b}, Output{"A Triangle area is: "} {}
    int area ()
      { return width*height/2; }
};

int main () {
  Output * ptr1 = new Rectangle(4,5);
  Output * ptr2 = new Triangle(4,5);

  ptr1->print();
  ptr2->print();

  // Causes core dump.  
  delete ptr1;
  delete ptr2;

  return 0;
}
Теги:
multiple-inheritance

2 ответа

3
Лучший ответ

В этом коде есть несколько основных проблем:

Во-первых, вы не должны использовать множественное наследование для этого. Это совершенно бесполезно и приведет к очень сложному отслеживанию ошибок.

Во-вторых, вам не нужно проверять значение nullptr перед удалением указателя - он избыточен, поскольку delete уже делает это.

В-третьих, ни один из ваших базовых классов не имеет виртуального деструктора. (текущая ошибка)

В-четвертых, вы нарушаете правило 3 в своем классе Output (и, вероятно, вам нужно будет использовать его во всех них).

В-пятых, предполагая, что string означает std::string. Нет причин для того, чтобы это была string* - просто используйте std::string и избегайте выделять и освобождать ее.

Я не исправлял проблемы с дизайном, но здесь исправлены проблемы с доступом к памяти и полиморфными проблемами.

#include <iostream>
#include <string>

using namespace std;

class Polygon 
{
  protected:
    int width, height;
  public:
    Polygon (int a, int b) : width(a), height(b) {}
    virtual ~Polygon() { } // needed!
    virtual int area() = 0;
};

class Output 
{
  private:
    std::string myString; // no need to be a pointer

  public:
    Output() {    }

    Output(const string& s) : myString(s) {   }

    virtual ~Output() {    } // also needed!
    virtual int area() = 0;
    void print () {
      cout << myString << this->area() << '\n';
    }
};



class Rectangle: public Polygon, public Output 
{
  public:
    Rectangle (int a, int b) : Polygon(a,b), Output{"A Rectangle area is: "} {}
    int area () {
     return width*height;
   }
};

class Triangle: public Polygon, public Output  
{
  public:
    Triangle (int a, int b) : Polygon{a,b}, Output{"A Triangle area is: "} {}
    int area ()
      { return width*height/2; }
};

int main () 
{
  Output * ptr1 = new Rectangle(4,5);
  Output * ptr2 = new Triangle(4,5);

  ptr1->print();
  ptr2->print();

  // Causes core dump.  
  delete ptr1;
  delete ptr2;

  return 0;
}

EDIT: пример лучшего способа реализации желаемой программы можно найти здесь.

  • 0
    Создание виртуальных деструкторов было достаточно, чтобы исправить первоначальную проблему в моем отладчике, но все ваши пункты очень верны и должны быть учтены.
  • 0
    Это действительно модифицированный пример cplusplus.com, я не думаю, что я бы пошел по этому пути для наследования. Я заметил, в вашем коде вы удалили delete myString , это не приводит к утечке памяти? Фактическая ошибка была вызвана отсутствием виртуальных деструкторов в базовом классе, распределение std :: string работало правильно.
Показать ещё 4 комментария
2

Polygon класса Output и Polygon должны быть virtual:

class Output {
  private:
    std::string* myString;

  public:
        // ...

    virtual ~Output() { 
 // ^^^^^^^
    }
};

Также обратите внимание: вместо использования указателя std::string* вы можете просто использовать std::string myString; член:

  private:
    std::string myString;

и оставьте delete myString; чтобы получить new string() и delete myString; право для любых случаев.

  • 0
    Но будет ли виртуальный деструктор для Output также вызывать деструктор OUtput по умолчанию?
  • 0
    Ах, я вижу, он все еще вызывается соответствующим образом. Спасибо!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню