如何用SWIG为Python包装带std::shared_ptr输出引用的C++ void函数
要实现Python中通过p = makeWidget()获取Widget的智能指针,核心是用SWIG typemap处理C++函数的引用型输出参数,同时正确管理shared_ptr的生命周期,避免段错误。以下是完整的解决方案:
1. 编写SWIG接口文件(widget.i)
%module widget // 引入SWIG对std::shared_ptr的支持 %include <std_shared_ptr.i> %shared_ptr(Widget) // 输入typemap:创建空shared_ptr作为引用参数的载体,标记无需Python传参 %typemap(in, numinputs=0) std::shared_ptr<Widget>& OUTPUT (std::shared_ptr<Widget> temp) { $1 = &temp; } // 输出typemap:将函数修改后的shared_ptr转为Python对象返回 %typemap(argout) std::shared_ptr<Widget>& OUTPUT { PyObject* obj = SWIG_NewPointerObj( SWIG_as_voidptr($1->get()), $descriptor(Widget*), SWIG_POINTER_OWN ); $result = obj; } // 声明C++结构体与函数 struct Widget { int value; }; void makeWidget(std::shared_ptr<Widget>& OUTPUT);
关键typemap解释
numinputs=0:告诉SWIG这个参数不需要Python传入,实现无参调用makeWidget()- 临时变量
temp:创建一个空的std::shared_ptr<Widget>,确保函数有有效的引用可以修改,避免野指针导致的段错误 SWIG_POINTER_OWN:标记Python拥有该对象的所有权,SWIG会自动协调Python引用计数与C++ shared_ptr的生命周期
2. C++实现代码(widget.cpp)
#include "widget.h" void makeWidget(std::shared_ptr<Widget>& out_ptr) { out_ptr = std::make_shared<Widget>(); out_ptr->value = 42; // 示例初始化值 }
对应的头文件(widget.h):
#include <memory> struct Widget { int value; }; void makeWidget(std::shared_ptr<Widget>& out_ptr);
3. 编译与测试
编译命令
# 生成SWIG包装代码 swig -python -c++ widget.i # 编译C++代码与包装代码 g++ -fPIC -c widget.cpp widget_wrap.cxx -I/usr/include/python3.10 # 替换为你的Python头文件路径 # 生成共享库 g++ -shared widget.o widget_wrap.o -o _widget.so
Python测试
import widget # 无参调用获取Widget实例 p = widget.makeWidget() print(p.value) # 输出:42
这个方案无需手动修改SWIG生成的包装代码,就能正确实现Python无参调用并返回智能指针包装的Widget对象,彻底解决之前的段错误问题。
内容的提问来源于stack exchange,提问作者Lars Ericson
相关产品推荐
相关产品推荐

