You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

pybind11绑定返回堆分配裸指针的C++函数时内存管理问题

问题描述

维护老旧C++代码时,遇到pybind11绑定后对象析构相关崩溃问题:

原C++函数返回堆分配裸指针:

MyClass* func(){
    MyClass* myPtr = new MyClass();
    return myPtr;
}

pybind11绑定类与函数的代码:

// 类绑定
py::class_<MyClass>(m, "PyClass")
// 方法和属性定义...

// 函数绑定
m.def("get_object", &func);

代码编译通过且首次运行正常,但后续会崩溃。推测是对象未被释放,尝试用std::unique_ptr结合返回策略修复但无效:

m.def("get_object_smart", [](){
        auto a = std::unique_ptr<MyClass>(func());
        return a;
    }, py::return_value_policy::copy); // 也试过take_ownership

疑问:如何让pybind11正确调用对象的析构函数?堆上用new分配的对象处理方式是否有区别?


解决方案

核心问题

pybind11对裸指针的默认返回策略是reference_internal,不会接管对象所有权,导致Python侧无法触发C++析构函数,内存泄漏累积后引发崩溃。而你尝试std::unique_ptr时选错了返回策略,反而引发新的问题。

正确处理方式

方式1:直接修改裸指针绑定的返回策略

无需包装unique_ptr,直接给裸指针绑定指定take_ownership返回策略,让pybind11接管对象所有权,Python垃圾回收触发时会自动调用C++析构函数:

m.def("get_object", &func, py::return_value_policy::take_ownership);

方式2:用std::unique_ptr正确绑定

如果要通过智能指针传递,不需要额外指定错误的返回策略(pybind11对unique_ptr有默认处理逻辑,会自动接管所有权),或者显式指定take_ownership即可,不要使用copy(copy会尝试复制对象,若MyClass无合适拷贝构造函数会出错):

m.def("get_object_smart", [](){
    return std::unique_ptr<MyClass>(func());
});
// 也可以显式指定(非必须):
// m.def("get_object_smart", [](){
//     return std::unique_ptr<MyClass>(func());
// }, py::return_value_policy::take_ownership);

关键说明

  • 堆上用new分配的对象,只要让pybind11获得所有权,就会在Python对象被垃圾回收时调用delete触发析构。
  • py::return_value_policy::take_ownership的作用是告知pybind11:返回对象的所有权转移给Python侧,由Python负责后续销毁。
  • 返回std::unique_ptr时,pybind11会自动识别并接管所有权——因为unique_ptr本身是独占所有权的智能指针,返回时会将所有权转移给pybind11的内部管理结构。

内容的提问来源于stack exchange,提问作者Ivan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 02:50:05