如何用Cython包装C++的std::shared_ptr与std::vector并简化初始化?
封装
TypeToWrap并实现Python风格的初始化与操作 首先明确:TypeToWrap是std::shared_ptr<std::vector<Value>>的别名,要让它在Python里像数组一样便捷使用,需要在Cython里做两层包装——先封装智能指针+vector的组合,再给ClassToWrap做适配。下面是具体实现步骤:
1. 声明C++类型依赖
先在Cython文件中引入C++标准库头文件,声明目标ClassToWrap模板类:
# distutils: language = c++ from libcpp.vector cimport vector from libcpp.memory cimport shared_ptr # 引入你的C++类头文件 cdef extern from "your_class_header.h": template <typename Value> class ClassToWrap: # 声明TypeToWrap类型别名 ctypedef shared_ptr[vector[Value]] TypeToWrap # 声明构造函数 ClassToWrap(TypeToWrap data)
2. 封装TypeToWrap为Python可操作类
写一个模板化的Cython类,把shared_ptr<vector<Value>>包装起来,实现Python序列接口(索引、迭代、长度等),让它支持列表式初始化和赋值:
cdef class WrappedTypeToWrap[Value]: cdef shared_ptr[vector[Value]] _inner_ptr def __cinit__(self, sequence=None): # 初始化智能指针和底层vector self._inner_ptr = shared_ptr[vector[Value]].__new__(shared_ptr[vector[Value]]) self._inner_ptr.reset(new vector[Value]()) # 支持从Python序列(列表/元组)直接初始化 if sequence is not None: for item in sequence: self._inner_ptr.get().push_back(Value(item)) # 实现索引访问 def __getitem__(self, int idx): if idx < 0 or idx >= self._inner_ptr.get().size(): raise IndexError("Index out of range") return self._inner_ptr.get()[idx] # 实现索引赋值 def __setitem__(self, int idx, value): if idx < 0 or idx >= self._inner_ptr.get().size(): raise IndexError("Index out of range") self._inner_ptr.get()[idx] = Value(value) # 支持Python循环迭代 def __iter__(self): cdef int i for i in range(self._inner_ptr.get().size()): yield self._inner_ptr.get()[i] # 动态添加元素 def append(self, value): self._inner_ptr.get().push_back(Value(value)) # 获取容器长度 def __len__(self): return self._inner_ptr.get().size()
3. 封装ClassToWrap类
让ClassToWrap的Python包装类接受上面的WrappedTypeToWrap实例,完成与C++类的对接:
cdef class WrappedClassToWrap[Value]: cdef ClassToWrap[Value]* _cpp_obj def __cinit__(self, WrappedTypeToWrap[Value] data): # 传入TypeToWrap类型的智能指针 self._cpp_obj = new ClassToWrap[Value](data._inner_ptr) def __dealloc__(self): # 释放C++对象内存 del self._cpp_obj
4. 实例化具体类型
Cython模板需要实例化为具体类型才能在Python中调用,比如针对int类型:
# 导出int版本的包装类供Python使用 WrappedTypeToWrapInt = WrappedTypeToWrap[int] WrappedClassToWrapInt = WrappedClassToWrap[int]
Python侧使用示例
现在你可以像操作普通Python列表一样使用封装后的类型:
# 从列表初始化TypeToWrap data = WrappedTypeToWrapInt([10, 20, 30]) # 循环赋值修改元素 for i in range(len(data)): data[i] = data[i] + 5 # 遍历输出结果 for num in data: print(num) # 输出15, 25, 35 # 动态添加元素 data.append(40) print(data[-1]) # 输出40 # 创建ClassToWrap实例 cpp_obj = WrappedClassToWrapInt(data)
关键注意点
- 类型转换:基础Python类型(int、float等)可自动转换为C的
Value类型;如果是自定义类型,需要额外实现Python到C类型的转换逻辑。 - 内存管理:
shared_ptr会自动管理vector的内存,Cython包装类的__dealloc__负责释放ClassToWrap对象,无需手动干预。 - 多维数组支持:如果需要多维数组,可将
Value替换为vector<InnerValue>,嵌套使用WrappedTypeToWrap即可,比如WrappedTypeToWrap[vector[int]],Python侧用嵌套列表初始化。
内容的提问来源于stack exchange,提问作者Giovanni Barbarani
相关产品推荐
相关产品推荐

