对象销毁后调用虚函数触发纯虚函数调用崩溃,因析构后vptr被重置为基类虚表,其函数项指向__cxa_pure_virtual;此时通过残留指针调用虚函数会直接abort,常见于delete后未置空、placement new后仅析构未释放、多线程竞态等场景。

对象销毁后调用虚函数直接触发纯虚函数调用崩溃
因为对象内存虽未被操作系统回收(比如在栈、内存池或未清零的堆块中),但其虚表指针(vptr)已被析构函数重置为基类的虚表——而该虚表中对应函数项指向的是 __cxa_pure_virtual,不是实际实现。一旦通过残留指针调用虚函数,就会跳转到这个终止处理函数,程序立刻 abort。
delete 后仍持有指针是典型诱因
常见于以下场景:
- 用
new分配对象,delete后未将指针置为nullptr,后续又误用该指针调用虚函数 - 对象在内存池(如
placement new)中构造,显式调用析构函数(obj->~Derived())但未释放底层内存,此时指针仍可解引用,但虚表已失效 - 多线程中一个线程刚
delete完对象,另一线程还没来得及检查就访问了该指针
注意:这不是“野指针访问导致段错误”,而是 C++ 运行时主动检测到非法虚调用后调用 std::terminate() —— 崩溃堆栈里通常能看到 __cxa_pure_virtual。
构造/析构过程中调用虚函数同样危险
即使对象还没被销毁,只要它处于“半构造”或“半析构”状态,虚表尚未就绪或已被破坏,调用虚函数也会落入纯虚陷阱:
立即学习“C++免费学习笔记(深入)”;
- 在基类构造函数中调用虚函数 → 此时派生类部分未构造,虚表指向基类,若该函数是纯虚,则崩溃
- 在基类析构函数中调用虚函数 → 派生类部分已析构,虚表可能已退回到基类层级,同样可能调用到纯虚函数
- 派生类构造函数体中调用虚函数是安全的(此时虚表已切换),但基类构造函数里绝对不行
为什么智能指针不能完全防住这个问题
std::unique_ptr 或 std::shared_ptr 确保析构自动发生,但不阻止你拿到裸指针后继续使用:
auto ptr = std::make_unique<derived>(); Base* raw = ptr.get(); ptr.reset(); raw->foo(); // 崩溃</derived>-
std::shared_ptr的控制块还在,但对象本体已析构,get()返回的裸指针已失效 - 自定义删除器若没正确同步状态,也可能让外部指针“以为对象还活着”
真正关键的不是“谁删的”,而是“删完之后还有没有人试图用它”——这点永远要靠逻辑约束和 RAII 边界意识,不是靠工具自动兜底。


















