Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > delete object with non-virtual destructor = UB ?


Автор: borisbn 6.10.2012, 11:57
Здравствуйте. Столкнулся с тем, что gcc на такой код
Код
struct Base {
    virtual void destroy() = 0;
};
struct Deriv : public Base {
    virtual void destroy() {
        delete this;
    }
    ~Deriv() { cout << "Deriv::~Deriv" << endl; }
};

int main()
{
   Base * a = new Deriv();
   a->destroy();
}

даёт такой warning
Цитата
warning: deleting object of polymorphic class type 'Deriv' which has non-virtual destructor might cause undefined behaviour [-Wdelete-non-virtual-dtor]

Если бы я написал delete a; - у меня бы не было вопросов, в чём я не прав - в Base нужно добавить вирт.деструктор... это понятно. Непонятно следующее - откуда в приведённом коде UB ?

Я тут немного поэкспериментировал - добавил в Base и в Deriv классик, который печатает что-то в своём конструкторе и деструкторе - отрабатывают все 4
Код
struct TracerBase
{
   TracerBase() { cout << "TracerBase::TracerBase()" << endl; }
   ~TracerBase() { cout << "TracerBase::~TracerBase()" << endl; }
};

struct Base {
    virtual void destroy() = 0;
    TracerBase m_tracer;
};

struct TracerDeriv
{
   TracerDeriv() { cout << "TracerDeriv::TracerDeriv()" << endl; }
   ~TracerDeriv() { cout << "TracerDeriv::~TracerDeriv()" << endl; }
};

struct Deriv : public Base
{
    virtual void destroy() {
        delete this;
    }
    ~Deriv() { cout << "Deriv::~Deriv" << endl; }
    TracerDeriv m_tracer;
};

int main()
{
   Base * a = new Deriv();
   a->destroy();
}

http://liveworkspace.org/code/f476a3f7cf08e0da9929fee22c25af52
Вывод
Цитата
TracerBase::TracerBase()
TracerDeriv::TracerDeriv()
Deriv::~Deriv
TracerDeriv::~TracerDeriv()
TracerBase::~TracerBase()


Вопрос: если не вызывать в явную деструктор базового класса, то в чём же тут UB ?
Спасибо.

Автор: boostcoder 6.10.2012, 12:31
Цитата(borisbn @  6.10.2012,  11:57 Найти цитируемый пост)
warning: deleting object of polymorphic class type 'Deriv' which has non-virtual destructor might cause undefined behaviour [-Wdelete-non-virtual-dtor]

эта проверка появилась вроде только в 4.7.2, если не ошибаюсь.
Цитата(borisbn @  6.10.2012,  11:57 Найти цитируемый пост)
откуда в приведённом коде UB ?

ну ,компилятор справедливо предполагает, что раз уж ты используешь new, то где-то должен быть delete ;)

Цитата(borisbn @  6.10.2012,  11:57 Найти цитируемый пост)
если не вызывать в явную деструктор базового класса, то в чём же тут UB ?

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

Автор: borisbn 6.10.2012, 13:50
Цитата(boostcoder @  6.10.2012,  12:31 Найти цитируемый пост)
наследники виртуальных классов обязаны реализовывать свой виртуальный деструктор

хммм. добавил virtual в деструктор Deriv и warning пропал... чего-то я недопонимаю  smile
Если в базовом нет вирт.деструктора, то какая разница виртуальный он в наследнике или нет.  smile 

Автор: boostcoder 6.10.2012, 14:31
Цитата(borisbn @  6.10.2012,  13:50 Найти цитируемый пост)
Если в базовом нет вирт.деструктора, то какая разница виртуальный он в наследнике или нет

в базовом он быть не обязан. а в наследниках обязан.
не знаю как объяснить, почему. а своими словами объяснять долго...

Автор: tzirechnoy 6.10.2012, 19:10
При наличии деструктора у потомка и неперегружэнного destroy(), этот destroy() вызовет не тот деструктор.

Автор: Леопольд 6.10.2012, 21:40
может поэтому?
Код

#include <iostream>

using std::cout;
using std::endl;

struct Base {
    virtual void destroy() = 0;
};

struct Deriv : public Base {
    virtual void destroy() {
        delete this;
    }
    ~Deriv() { cout << "Deriv::~Deriv" << endl; }
};

struct Final: public Deriv
{
    ~Final() { cout << "Final::~Final" << endl; }
};

int main()
{
   Base * a = new Final();
   a->destroy();
}

http://liveworkspace.org/code/b65e4d394e7c26e0b284536b3441c5b5

Автор: borisbn 7.10.2012, 07:45
Спасибо. Понятно.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)