如何不修改C++代码将SWIG生成的Python对象转为Interface指针?
嘿,我碰到过一模一样的问题!咱们先捋清楚为啥会报错,然后给你两个不用改C++代码的解决办法。
首先说问题根源:你调用了Implementation().__disown__(),这个方法会把Python对象和底层C对象的绑定关系断开,返回的是个原始指针的包装,但SWIG的类型系统没法自动识别这个指针就是Interface*。而且说实话,绝大多数情况下你根本不需要手动调用__disown__——SWIG会自动帮你管理director对象的生命周期,除非你明确要让C代码完全接管这个对象的所有权。
办法1:直接删掉__disown__(最省心)
这是最简单的解决方式,SWIG会自动处理类型转换和内存管理:
import interface class Implementation(interface.Interface): def __init__(self): super().__init__() self.__something = 1 def blah(self): print("called python version") i = Implementation() # 别再调用__disown__啦 u = interface.User() u.callBlah(i)
这样Python对象i会被SWIG自动包装成Interface*类型传给C++的callBlah方法,同时SWIG会盯着对象的引用计数,不会出现内存泄漏的问题。
办法2:必须手动管所有权?用SWIG的类型转换函数
如果你确实需要让C代码接管这个对象(比如C方法会把指针存起来后续用),那可以用SWIG自动生成的_cast函数来显式转换类型:
import interface class Implementation(interface.Interface): def __init__(self): super().__init__() self.__something = 1 def blah(self): print("called python version") impl = Implementation() # 把__disown__返回的指针转成Interface*类型的SWIG对象 i = interface.Interface._cast(impl.__disown__()) u = interface.User() u.callBlah(i)
这个_cast函数是SWIG为每个类自动生成的,能帮你把原始指针包装成正确的类型,让C++方法能识别。
额外提一句:那个SWIG警告别忽略
你编译的时候收到的Warning 514: Director base class Interface has no virtual destructor是个大问题——如果C代码通过Interface*指针删除对象,会触发未定义行为(因为没有虚析构函数,不会调用Python子类的析构逻辑)。虽然你说不能改C代码,但如果有机会的话,一定要给Interface加个虚析构函数:
class Interface { public: virtual void blah() = 0; virtual ~Interface() = default; // 加这个虚析构 };
要是真的没法改C代码,那一定要确保**永远不要让C代码删除这个Interface*指针**,只能让Python端来管理它的生命周期。
内容的提问来源于stack exchange,提问作者Hei

