pure vitual function called导致的异常

本文详细解释了在C++中派生类析构函数调用基类析构函数时,虚函数表指针的修改及其对程序的影响。探讨了构造和析构函数中调用虚函数可能导致的‘PureVirtualFunctionCalled’错误,并提供了避免此类错误的建议。同时,文章总结了网络上的相关资源和实例,帮助开发者理解和预防这类常见问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


2012-8-22
cswuyg
1.      派生类对象析构时,基类析构函数执行的前期会修改对象的虚函数表指针值

        一般情况下(特指基类不使用novtable属性),debug编译出来的exe,派生类对象的析构,在析构基类部分的时候,对象的虚函数表指针值项会被修改成基类的虚函数表地址,然后再执行基类的析构函数体。

其中高亮的那一行是修改对象的虚函数表指针值为基类虚函数表地址

         release下编译出来的就不是这样子。以一个小测试程序为例,编译器做了优化,并没有在调用基类析构函数时做赋值。但不确定编译器是否会一直做优化,因为看到了派生类析构函数体实质内容执行之前对虚函数表指针值做了一次赋值,那么为什么在基类析构函数体实质内容执行之前就不需要赋值?编译器优化的事情就不说了,吃力不讨好。下边图示调用派生类析构函数时做的事情,包括派生类部分和基类部分。

标红的地址是派生类析构函数执行前期对虚函数表指针值赋值

注1:novtable我是从这篇文章里看到的:

http://www.cnblogs.com/chio/archive/2007/09/09/887598.html

注2:我使用的工具为VS2005、OllyDbg。

2.不要在构造函数、析构函数里调用虚函数

根据网络上一些文章的讲解,可能出现“Pure Virtual Function Called”的错误情况有5种:

1) 基类构造器直接调用虚函数;

2)基类析构器直接调用虚函数;

3)基类构造器间接调用虚函数;

4) 基类析构器间接调用虚函数;

5)通过悬垂指针(dangling pointer,又称野指针)调用虚函数。

         “dangling pointer”导致的“Pure Virtual Function Called”,在vs2005上测试了并没有出现,因为delete之后,对象的内存值会被修改为某些标志值。可能在其它编译器上会出现。

        一些书籍:

        《Effective C++第三版》 建议不要在构造、析构时调用虚函数。
        《深度探索C++对象模型》在讲解vptr部分时,也分析过在基类构造函数里调用虚函数会出现的情况,它说,这些调用都是“静态决议”的,无论直接或间接调用虚函数。但实际上可能不是这样子,这取决于编译器的实现。VS2005就不是,直接调用会静态绑定,而间接调用是动态绑定。

        如果是小程序的话,这种错误很容易发现,如果工程大了,这样的错误非常难找到。所以,书里的建议必须重视。优秀的程序员不是懂得“回”字有多少种写法,而是有很多写好工程的好习惯。

 3.      网络上一些不错的总结:

http://www.artima.com/cppsource/pure_virtual.html  (非常完整)

http://www.codeproject.com/Articles/14879/Pure-Virtual-Function-Call (很简单容易看)

http://blog.youkuaiyun.com/kikikind/article/details/2645316 (中文的总结汇总,很简单容易看懂)

http://www.cnblogs.com/chio/archive/2007/09/09/887598.html (分析汇编,底层而完善)

 

 

一些短小的验证代码:

http://files.cnblogs.com/cswuyg/%E7%94%B1Pure_Virtual_Function_Called%E8%80%83%E8%99%91%E5%88%B0%E7%9A%84.rar



文章内容来不及看,先保存一下。

http://technet.microsoft.com/zh-cn/library/t296ys27(v=vs.80)


这是msdn上用_set_purecall_handled来捕捉异常的一个例子。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值