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

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

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 не уничтожается правильно. Почему?

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

Спасибо,

P.S. Я уже знаю об устаревшем std::auto_ptr<>() использовании:)

Ответы [ 3 ]

5 голосов
/ 13 марта 2012

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

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

2 голосов
/ 13 марта 2012

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

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

1 голос
/ 13 марта 2012

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...