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

使用nanobind从C++向Python返回自有内存ndarray的技术问询

使用nanobind从C++返回numpy ndarray的正确方式

你的第一个代码示例存在严重问题:std::array是栈上分配的内存,函数返回后栈帧会被销毁,Python拿到的ndarray会指向无效内存,导致未定义行为(崩溃、数据错乱等),这不是内存泄漏,而是悬垂指针问题。

第二个代码示例无法运行的原因是:默认构造的nb::ndarray并没有分配内存,result.data()会返回空指针,后续访问自然出错。

针对你“返回指定大小、自行填充数据、不由C管理内存”的需求,最优方案是让Python/numpy负责内存分配,C仅负责填充数据,具体实现如下:

正确代码示例

固定大小数组

.def("test", []() {
    constexpr size_t arr_size = 100;
    // 创建空的numpy ndarray,内存由numpy分配(Python管理)
    auto result = nb::ndarray<double, nb::numpy>::empty({arr_size});
    // 填充数据,这里可以替换为你的自定义填充逻辑
    std::fill(result.data(), result.data() + result.size(), 100.0);
    return result;
})

动态大小数组

如果需要根据参数决定数组大小:

.def("test_dynamic", [](size_t arr_size) {
    auto result = nb::ndarray<double, nb::numpy>::empty({arr_size});
    std::fill(result.data(), result.data() + result.size(), 100.0);
    return result;
})

关键细节说明

  • nb::ndarray::empty({size})会让numpy分配符合要求的内存,返回的ndarray所有权完全属于Python,C++无需关心内存释放。
  • 填充数据时直接操作result.data()返回的指针即可,和操作普通C数组没有区别。

可选方案:转移C堆内存所有权(如果必须用C分配)

如果你的数据必须在C中分配(比如从其他C逻辑获取堆内存),可以通过**胶囊(capsule)**把内存所有权转移给Python,让Python负责释放:

.def("test_heap_data", []() {
    size_t arr_size = 2;
    // C++堆上分配内存
    double* data = new double[arr_size]{10.0, 20.0};
    // 创建胶囊,定义内存释放逻辑
    nb::capsule free_capsule(data, [](void* p) {
        delete[] static_cast<double*>(p);
    });
    // 返回ndarray,关联胶囊作为所有者
    return nb::ndarray<double, nb::numpy>(data, {arr_size}, free_capsule);
})

这种方式下,C++无需手动释放内存,当Python的ndarray被垃圾回收时,胶囊的销毁函数会自动执行delete[]。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 15:18:22