Сбой кода, когда производный класс «деструктор является виртуальным, а базовый класс» dtor не является - PullRequest
6 голосов
/ 27 мая 2011

Я попробовал следующий код на gcc 4.4.5.

Если элемент 'data' отсутствует, код выполняется нормально, но при его наличии происходит сбой. Также не происходит сбой, когда dtor производного класса не является виртуальным.

Я знаю, что поведение будет неопределенным, как указано в C ++ 03 (5.3.5 / 3) в обоих случаях, но все же кто-то может дать мне некоторое объяснение, почему это сбой в последнем случае?

И да, я знаю, что UB означает, что все может произойти, но все же Я хотел бы знать подробности, связанные с реализацией.

#include<iostream>    
using std::cout;

struct base{
int data;
   base(){
      cout << "ctor of base\n";
   }
   ~base(){
      cout << "dtor of base\n";
   }
};

struct derived :  base{
   derived(){
      cout << "ctor of derived\n";
   }
   virtual ~derived(){
      cout << "dtor of derived\n";
   }
};

int main(){
   base *p = new derived;
   delete p;
}

Ответы [ 2 ]

10 голосов
/ 27 мая 2011

Если предположить, что происходит в моей системе (gcc 4.6.0, linux x86_64), то же самое, что и в вашей системе (она также аварийно завершает работу с data и работает без нее), деталь реализации заключается в том, что p делает не точка в начале блока памяти, выделенного для объекта типа derived.

Как сказал valgrind

Address 0x595c048 is 8 bytes inside a block of size 16 alloc'd

Вы можете убедиться в этом сами, если напечатаете значения указателей:

derived * d = new derived;
std::cout << d << '\n';
base *p = d;
std::cout << p << '\n';

И причина этого в том, что макет объекта в gcc {vtable, base, output}}

Когда base пуст, размеры {vtable, base, производный} и {base} оказываются одинаковыми, потому что выделение объекта пустого класса занимает ненулевое число байтов, что в обоих случаях оказывается равным.

Когда производная не имеет виртуальных функций, vtable отсутствует, адреса снова совпадают, и удаление завершается успешно.

2 голосов
/ 27 мая 2011

размер этих двух типов не совпадает, и макет в вашем примере должен отличаться.

вы сравниваете типы pod с типом с vtable (макет и смещения определяются реализацией).когда вызывается деструктор, предполагается, что адрес неявного this имеет расположение base, но на самом деле это derived.то, что выполнено, эквивалентно записи / чтению с неверного адреса.

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