如何用Cython转换接收并返回std::vector的C++函数?
解决方案
前置准备:补充C++头文件
首先需要为你的C++函数创建头文件cpp_func.h,供Cython调用:
#include <vector> std::vector<std::vector<float>> my_cpp_function(const size_t& p_num, const std::vector<float>& x, const std::vector<std::vector<float>>& table);
问题1:Numpy数组转C++ std::vector
Numpy数组的memoryview无法直接传递给接收std::vector的C++函数,必须进行类型转换。我们可以用memcpy实现高效拷贝,避免循环赋值的开销:
问题2:C++二维vector转memoryview
二维std::vector的内存是非连续的(每个子vector独立分配),而Numpy/memoryview要求连续内存。需要先创建连续内存的Numpy数组,再将vector数据拷贝进去。
问题3:高效转换优化
- 输入侧:用
memcpy替代循环赋值,提前调用vector.reserve()避免扩容时的内存重分配 - 输出侧:同样用
memcpy完成数据拷贝,返回的memoryview可直接被Numpy复用,无需额外拷贝
修改后的完整Cython代码(cython_v1.pyx)
import numpy as np cimport numpy as np import cython from libcpp.vector cimport vector from libc.string cimport memcpy # 声明C++函数接口 cdef extern from "cpp_func.h": vector[vector[float]] my_cpp_function(const size_t& p_num, const vector[float]& x, const vector[vector[float]]& table) @cython.boundscheck(False) @cython.wraparound(False) cpdef float[:, ::1] my_cython_func(size_t p_num, float[:] x, float[:, ::1] table): # 1. 转换一维输入x为C++ vector cdef vector[float] cpp_x cpp_x.reserve(x.shape[0]) memcpy(&cpp_x[0], x.data(), x.shape[0] * sizeof(float)) # 2. 转换二维输入table为C++二维vector cdef vector[vector[float]] cpp_table cpp_table.reserve(table.shape[0]) cdef int i, cols = table.shape[1] for i in range(table.shape[0]): cdef vector[float] row row.reserve(cols) memcpy(&row[0], table[i].data(), cols * sizeof(float)) cpp_table.push_back(row) # 调用C++核心函数 cdef vector[vector[float]] cpp_H = my_cpp_function(p_num, cpp_x, cpp_table) # 3. 转换C++输出为连续内存的memoryview cdef int rows = cpp_H.size() if rows == 0: return np.empty((0, 0), dtype=np.float32).view() cdef int out_cols = cpp_H[0].size() # 创建连续内存的Numpy数组 cdef np.ndarray[float, ndim=2, mode="c"] result_np = np.empty((rows, out_cols), dtype=np.float32) cdef float[:, ::1] result_view = result_np # 高效拷贝每一行数据 for i in range(rows): memcpy(&result_view[i, 0], cpp_H[i].data(), out_cols * sizeof(float)) return result_view
编译脚本(setup.py)
用于将Cython和C++代码编译为Python可导入模块:
from setuptools import setup, Extension from Cython.Build import cythonize import numpy as np ext = Extension( "cython_v1", sources=["cython_v1.pyx", "cpp_func.cpp"], language="c++", include_dirs=[np.get_include()], extra_compile_args=["-O3"], # 开启编译优化 ) setup(ext_modules=cythonize(ext))
编译与调用
- 编译模块:运行
python setup.py build_ext --inplace - Python调用代码无需修改,
np.asarray(my_cython_func(...))会直接复用memoryview的内存,无额外拷贝开销
内容的提问来源于stack exchange,提问作者Ong Beng Seong
相关产品推荐
相关产品推荐

