试图用pybind11包装PhysX库,然后在Python里用。结果在Python里报了一个从没见过的错误,RuntimeError: Access violation - no RTTI data!,这里看看到底是哪里来的。

自动cast到派生类

pybind11有个特性,如果返回一个多态类的指针,那么会试图返回成最外层派生类的对象。例如,Pet是多态基类(至少有一个virtual函数,例如destructor),Dog继承自Pet。一个create_pet函数返回一个Pet*。如果这个Pet实际上是个Dog,那么Python层拿到的就是一个Dog实例。

思考一下,这个特性也是不得已而为之,因为Python里没有dynamic cast和指针操作,如果返回一个Pet,那么没法只用Python来cast成一个Dog。(当然,从某种角度看在这里使用dynamic_cast本身就是不大好的。)

RTTI开关

包装一个多态类的时候,报了一个类似这样的错误:

Traceback (most recent call last):File "E:WorkPythonpybind11rttibuildDebugtest_rtti.py", line 3, in <module>pet = rtti.create_pet()
RuntimeError: Access violation - no RTTI data!

大概是从C++的Pet*转成Python对象的过程中报的。

发现cl编译器有个开关,/GR/GR-,前者是打开RTTI,后者是关闭RTTI,默认是前者。如果使用了/GR-,就会报上面的错误。可以在CMake GUI的CMAKE_CXX_FLAGS 里设置成关闭RTTI

dynamic_cast试验

做一个简单的试验,写个多态Pet,Dog继承Pet。

struct Pet {virtual ~Pet() {};
};struct Dog : public Pet {};

然后,试图把一个Pet*cast成Dog*

    Dog dog;Pet* p_pet = &dog;Dog* p_dog = dynamic_cast<Dog*>(p_pet); 

如果使用/GR-参数,也就是关闭RTTI,果然crash了。调试,发现抛出了一个异常。

再点一下continue,有了异常的类型,是一个std::__non_rtti_object 异常对象。

既然是异常,就可以catch,catch一下把what打印出来

 try {p_dog = dynamic_cast<Dog*>(p_pet);}catch (std::exception & e) {std::cout << "[exception]" << typeid(e).name() << ", " << e.what() << "n";}

输出的是

[exception]class std::__non_rtti_object, Access violation - no RTTI data!

果然和Python里抛出的异常完全对的上。

实际上,在编译的时候就已经报了警告了

这个std::__non_rtti_object是个啥,可以直接看下头文件

可以看到,继承了标准库里的std:bad_typeid 这个异常。那么,这个报错的字符串,总要存在哪里吧?用文本编辑器打开vcruntime140.dll这个文件,搜一下“RTTI”,这就是根源了。

编译好的库不受影响

其实,不使用dynamic_cast,直接使用typeid 也会报错

std::cout << typeid(*p_pet).name() << "n";

也会抛出同样的异常。那,为什么上面的typeid(e).name()没有报错呢?大概是因为这个vcruntime140.dll本身在编译的时候,是开了RTTI的。

解决办法

怎么解决这个报错呢,显然,可以打开RTTI。不只是编译wrapper的时候打开,在编译PhysX库的时候也要打开。

不过,既然人家默认是关闭的,那肯定有关闭的理由。RTTI是有开销的。朴素的想,"RTTI"并不是高深的概念。最简单的,把所有可能出现的末端派生类的名字,放到一个巨大的enum里;类里面加个成员mConcreteType,再加个类似getConcreteType的函数,配合一个巨大switch(或者模板之类),也可以实现基本的功能。PhysX就是这么干的,看上去。快,省空间,够用。可以翻下这两个文件PxBase.h和PxTypeInfo.h。PxBase里有个is<T>()函数,可以实现类似dynamic_cast的效果。

在pybind11的源码里,搜索typeid和dynamic_cast,也就知道这个no RTTI的异常大概是哪里抛出来的了。附近的注释里也有写,可以通过模板特化,来实现对无RTTI信息的类层次实现有RTTI的效果。可以搜polymorphic_type_hook 来看。这里面还有个黑科技,就是dynamic_cast<const void*>(src),可以把src指针cast成最外层的派生类,来实现返回Pet*,出来个Dog的效果。但是,如果想绕过对typeid的调用,怕是有点麻烦了。

参考

/GR编译选项

https://docs.microsoft.com/en-us/cpp/build/reference/gr-enable-run-time-type-information?view=vs-2019​docs.microsoft.com

typeid操作符

typeid Operator​docs.microsoft.com

dynamic_cast<void*>的使用

Everything you should know about the dynamic_cast and typeid tools. | C++ - don't panic!​blog.panicsoftware.com

cast函数_关闭RTTI后dynamic_cast和typeid报异常相关推荐

  1. RTTI、dynamic_cast、typeid、虚函数表

    一.RTTI RTTI(Run-Time Type Identification),通过运行时类型信息,程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型. Human* phu ...

  2. eslint常用设置;eslint关闭驼峰命名;eslint关闭全等于===校验;eslint关闭未定义变量报错;eslint关闭声明后未使用变量报错;eslint关闭单闭合标签校验;

    详细配置eslint操作可看此篇 eslint各种限制规则可看此篇 在 .eslintrc.js 文件修改规则:0关闭 1警告 2报错 module.exports = {root: true,par ...

  3. Th3.10:RTTI、dynamic_cast、typeid简介

     本博客将记录:类的相关知识点的第10节的笔记! 今天 总结的这5个知识点都是之前我coding中接触得非常少的,因此务必要重视这一章! 今天总结的知识分为以下5个点: 一.RTTI是什么? 二.dy ...

  4. mysql cast报错_在mysql中使用cast函数报错

    今天遇到在使用mysql的cast函数报错的问题,这个函数的意思是把当前的字段转成某种类型的字段,我使用cast(xxxx as int) 这种方式,但是发现报错了,查阅资料发现 参考这个百度,总结来 ...

  5. 【TCP协议】主动方关闭连接后不能继续接收数据?

    如果你搜过TCP的四次挥手相关信息,你一定会看到类似这样的话:"主动方选择关闭连接后,被动方马上回ACK,此时可以继续传输数据,传完后再发送FIN" (图片来源:CS-Notes/ ...

  6. 【九】Python全栈之路--文件函数_函数参数

    文章目录 1. 文件相关函数 2. 函数_函数的参数 2.1 函数 2.2 函数的参数 3. 收集参数 4. 命名关键字_总结 4. 小练习 1. 文件相关函数 # ### 刷新缓冲区 "& ...

  7. oracle+cast函数+长度,oracle cast() 函数问题

    oracle cast() 函数问题 关键字: oracle cast() 函数问题 SQL> create table t1(a varchar(10)); Table created. SQ ...

  8. 设置Django关闭Debug后的静态文件路由

    Django在Debug模式关闭掉后请求静态文件时,返回404相应码,后台的请求url是"GET /static/css/404.css HTTP/1.1" 404 1217,找不 ...

  9. windows 改变文件大小 函数_手写 bind call apply 方法 与 实现节流防抖函数

    实现 bind call apply 方法 this 是什么? this是指包含它的函数作为方法被调用时所属的对象.这句话理解起来感觉还是很拗口的,但是如果你把它拆分开来变成这三句话后就好理解一点了. ...

最新文章

  1. 字节跳动高频算法题TOP100
  2. php循环输出标题,php-如何通过循环在同一标题下分组数据
  3. GotFocus和PreviewLeftButtonDown事件
  4. matlab里符号的写法,Matlab中特殊符号的写法
  5. kettle-实现每个分组的前N的数据
  6. Java render用法_SpringMVC ModelAndView的用法使用详解
  7. redis 系列27 Cluster高可用 (2)
  8. 实习小白::(转) Cocos2d-x 3.0 开发(十五)使用UILayout布局,制作对话界面
  9. UVa——110303 Common Permutation(字符串)
  10. 网平差中的基线定权(松弛因子)
  11. qemu-img 镜像转换工具使用
  12. 关于 Photoshop 图层
  13. 鸟枪换炮---IDEA
  14. Python的字典中动态添加键值对
  15. 华为hcia-datacom 学习日记
  16. 吉林大学计算机学院课程学分,吉林大学软件学院学分规定
  17. Java关键字-static
  18. 中国电信定制的中兴 ZXV10 B760H 机顶盒root全程记录
  19. java计算机毕业设计基于安卓Android的在线心理咨询与健康App
  20. 公司oa系统必须要服务器么,oa系统需要购置云服务器吗

热门文章

  1. 墨天轮社区专属福利:与作者互动问答,民工哥全新力作《Linux系统运维指南:从入门到企业实战》送上!...
  2. MySQL关于Table cache设置,看这一篇就够了
  3. 论文解读丨无参数的注意力模块SimAm
  4. 存算分离架构的高斯Redis,用强一致提供可靠保障
  5. CSS开发过程中的20个快速提升技巧
  6. 传统输电线路巡检难?无人机这回立了大功!
  7. 基于GaussDB(DWS)的全文检索特性,了解一下?
  8. 白皮书丨关于工业互联网,你想知道的都在这儿
  9. 人少钱少需求多的新项目该怎么带?看到这篇我心里有底了!
  10. 【华为云技术分享】如何使用pyCharm与ModelArts公有云服务联动开发,快速且充分地利用云端GPU计算资源