Я столкнулся с тем, что чисто виртуальные функции вызываются из-за разрушенных объектов, Len Holgate
уже есть очень хороший ответ, я хотел бы
добавить немного цвета с примером:
- Создается производный объект, и указатель (как базовый класс)
где-то сохранено
- Производный объект удален, но каким-то образом указатель
все еще упоминается
- Указатель, который указывает на удаленное производное
объект называется
Деструктор производного класса сбрасывает точки vptr в базовый класс vtable, который имеет чисто виртуальную функцию, поэтому, когда мы вызываем виртуальную функцию, она фактически вызывает чисто виртуальные.
Это может произойти из-за явной ошибки кода или сложного сценария состояния гонки в многопоточных средах.
Вот простой пример (компиляция g ++ с отключенной оптимизацией - простая программа может быть легко оптимизирована):
#include <iostream>
using namespace std;
char pool[256];
struct Base
{
virtual void foo() = 0;
virtual ~Base(){};
};
struct Derived: public Base
{
virtual void foo() override { cout <<"Derived::foo()" << endl;}
};
int main()
{
auto* pd = new (pool) Derived();
Base* pb = pd;
pd->~Derived();
pb->foo();
}
А трассировка стека выглядит так:
#0 0x00007ffff7499428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1 0x00007ffff749b02a in __GI_abort () at abort.c:89
#2 0x00007ffff7ad78f7 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3 0x00007ffff7adda46 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4 0x00007ffff7adda81 in std::terminate() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#5 0x00007ffff7ade84f in __cxa_pure_virtual () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#6 0x0000000000400f82 in main () at purev.C:22
Выделите:
если объект полностью удален, то есть вызывается деструктор и вызывается восстановление memroy, мы можем просто получить Segmentation fault
, поскольку память вернулась в операционную систему, и программа просто не может получить к ней доступ. Таким образом, этот сценарий «чисто виртуального вызова функции» обычно происходит, когда объект размещается в пуле памяти, в то время как объект удаляется, базовая память фактически не восстанавливается ОС, она все еще там доступна для процесса.