Почему отсутствие виртуального d-tor в g++ не уничтожает стеков, выделенных членам производного класса?

У меня есть следующий код:

struct Message
{
   explicit Message(const std::string& message) : selfMessage(message) {};
   ~Message() { std::cerr << "Message: " << selfMessage << std::endl; }
   const std::string selfMessage;
};

struct Foo
{
   Foo() : fooMessage("Foo") {}
   /// Destructor here is left intentionally non-virtual !!!
   ~Foo() { std::cerr << "~Foo" << std::endl; }

   Message fooMessage;
};

struct Bar : Foo
{
   Bar() : barMessage("Bar") {}
   ~Bar() { std::cerr << "~Bar" << std::endl; }
   Message barMessage;
};

int main()
{
  std::auto_ptr<Foo> foo(new Bar);
}

Я ожидаю следующий вывод:

Message: Bar
Message: Foo
~Foo()

Но на самом деле (код скомпилирован с gcc) не печатает Message: Bar так, насколько я понимаю barMessage не уничтожен правильно. Зачем?

AFAIK, не виртуальный d-tor, влияет только на вызов dtor производного класса - он никогда не будет вызываться, но как насчет членов, выделенных из стека производного класса?

Спасибо,

PS я уже знаю о устаревших std::auto_ptr<>() использование:)

3 ответа

Решение

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

Сдача std::auto_ptr шаблон для базового класса выходит из области видимости, когда он владеет объектом производного класса, имеет эффект вызова delete для типа указателя базового класса, когда фактический объект имеет тип производного класса.

В конечном счете, auto_ptr звонки delete myPtr (где myPtr является членом типа T*). Вызов delete где статический тип и динамический тип не совпадают, это неопределенное поведение. Это не просто случай, когда деструкторы производного класса не будут вызываться; это тот случай, когда может случиться что угодно. И делает, в случае более сложных иерархий наследования.

Это относится только к динамически размещенным экземплярам. Вызов delete для чего-то, что не было динамически размещено, является неопределенным поведением (и, как правило, вызывает все виды проблем). И кроме удаления, деструктор вызывается для объекта, а не указателя, поэтому статический тип и динамический тип идентичны.

Bar::barMessage не разрушается именно потому, что разрушение базы не является виртуальным. Указатель имеет тип Fooи при выходе из объема, std::auto_ptr укроп вызов delete на внутренний указатель, который является неопределенным поведением, и в этом случае уничтожит только Foo субобъект.

Обратите внимание, что не существует такого понятия, как выделение стека членами Barесть члены с автоматическим хранением, но в этом случае, поскольку весь объект был выделен динамически, то есть не в стеке, а в куче (C++ технически не имеет понятия о стеке / куче, но понимает, что все Bar объект распределяется динамически)

Другие вопросы по тегам