Если предположить, что происходит в моей системе (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 отсутствует, адреса снова совпадают, и удаление завершается успешно.