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

Pybind11如何将C++三维数组/数组指针无拷贝返回为Numpy数组

实现方案(无拷贝返回C++三维数组到Numpy)

核心原理是通过Pybind11提供的py::array_t类型直接封装C++侧的内存指针,正确配置形状、步长和内存所有权策略后,即可实现零拷贝映射为Python侧的Numpy数组。


1. 前置依赖与声明

首先在C++代码中引入必要头文件,简化命名空间调用:

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

namespace py = pybind11;

注意:如果要返回的C++数组是栈上分配的局部变量(例如函数内定义int arr[100][100][3]),绝对不能直接返回指针,函数退出后栈内存会被回收,Python侧访问会触发内存错误。栈上数组只能做拷贝返回,要实现零拷贝需要将数组改为静态存储、全局存储或者堆分配,保证返回Python后内存仍然有效。


2. 零拷贝返回实现示例

示例1:返回静态存储的三维数组

适合生命周期和程序运行周期一致的数组场景:

py::array_t<int> get_static_3d_array() {
    // 静态存储,程序运行期间内存不会释放
    static int arr[100][100][3];
    // 此处可添加arr的赋值、修改逻辑
    
    // 定义数组形状,三个维度分别为100、100、3
    const std::array<ssize_t, 3> shape = {100, 100, 3};
    // 定义每个维度的步长,单位为字节,int占4字节所以乘4
    const std::array<ssize_t, 3> strides = {
        100 * 3 * sizeof(int),
        3 * sizeof(int),
        sizeof(int)
    };

    // 静态数组不需要额外释放,传入空capsule即可
    return py::array_t<int>(
        shape,
        strides,
        &arr[0][0][0],
        py::capsule()
    );
}

示例2:返回堆分配的三维数组,自动管理内存

适合动态生成的数组场景,会在Python侧Numpy数组被垃圾回收时自动释放C++侧内存,避免泄漏:

py::array_t<int> get_heap_3d_array() {
    // 堆分配三维数组
    int (*arr)[100][3] = new int[100][100][3];
    // 此处可添加arr的赋值、修改逻辑

    const std::array<ssize_t, 3> shape = {100, 100, 3};
    const std::array<ssize_t, 3> strides = {
        100 * 3 * sizeof(int),
        3 * sizeof(int),
        sizeof(int)
    };

    // 自定义释放器,Python侧数组销毁时自动调用delete释放堆内存
    py::capsule deleter(arr, [](void *p) {
        delete[] static_cast<int(*)[100][3]>(p);
    });

    return py::array_t<int>(
        shape,
        strides,
        &arr[0][0][0],
        deleter
    );
}

3. 绑定到Pybind11模块

将函数绑定到你的模块即可在Python侧调用:

PYBIND11_MODULE(your_module_name, m) {
    m.def("get_static_3d_array", &get_static_3d_array, "Get static 3D int array as numpy array (zero copy)");
    m.def("get_heap_3d_array", &get_heap_3d_array, "Get heap allocated 3D int array as numpy array (zero copy)");
}

4. Python侧调用验证

import your_module_name
import numpy as np

arr = your_module_name.get_heap_3d_array()
print(arr.shape) # 输出 (100, 100, 3)
print(arr.dtype) # 输出 int32,和C++侧int类型对应
# 验证零拷贝:修改Python侧数组的值,C++侧对应内存会同步更新,反之亦然

关键注意事项

  • 如果你的C++数组是非连续存储的,只需要对应调整strides参数的数值即可正常映射
  • 如果确实需要返回栈上的局部数组,去掉py::array_t构造参数里的capsule即可,Pybind11会自动做内存拷贝返回
  • 零拷贝场景下不要在C++侧提前释放已经返回给Python的数组内存,否则会触发Python侧崩溃

内容的提问来源于stack exchange,提问作者Krishna Teja Nuthalapati

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 02:24:04