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

如何通过SWIG将Python列表转为std::vector<double>*传入C++构造函数

问题根源

SWIG默认的std::vector<double>* INPUT类型映射会创建临时vector对象:当调用函数/构造函数时,SWIG将Python列表转换为临时vector,传递指针给C++代码;调用结束后,SWIG会销毁这个临时vector。

对于成员方法(如SampleMethod),临时vector仅在方法执行期间有效,执行完毕销毁不会有问题;但构造函数会将这个临时vector的指针保存到m_v成员变量中,后续访问时临时vector已被销毁,指针变为野指针,从而导致异常值、乱码甚至段错误。

解决方案

由于无法修改C代码,我们需要在SWIG接口中调整类型映射逻辑,确保构造函数接收的vector不会被SWIG自动销毁,或让vector的生命周期与C对象绑定。以下提供两种可行方案:

方案1:使用OWN类型映射接管所有权

SWIG的OWN类型映射会告知SWIG:传递的指针指向的对象将被C++代码接管所有权,SWIG不会自动销毁它。修改example.i如下:

%module example

%{
    #include "example.hpp"
%}

%include "typemaps.i"
%include "std_vector.i"

%template(doublevector) std::vector<double>;

// 针对构造函数的vector指针参数,应用OWN类型映射
%apply std::vector<double> *OWN {std::vector<double>* v};

%include "example.hpp"

注意事项

  • 该方案会导致内存泄漏:C类SampleClass的代码中没有销毁m_v的逻辑,因此vector的内存不会被释放。如果你的实际场景中C类会负责销毁m_v,则此方案完全适用。

方案2:自定义构造函数包装(无内存泄漏)

通过%extend在SWIG中自定义构造函数,手动创建vector并将其生命周期与Python代理对象绑定,当Python代理被垃圾回收时自动销毁vector。修改example.i如下:

%module example

%{
    #include "example.hpp"
%}

%include "std_vector.i"
%template(doublevector) std::vector<double>;

// 手动包装SampleClass,自定义构造函数处理Python列表
class SampleClass {
public:
    std::vector<double>* m_v;

    // 自定义构造函数:接收Python列表,创建持久化vector
    %extend {
        SampleClass(PyObject* py_list) {
            // 校验输入类型
            if (!PyList_Check(py_list)) {
                PyErr_SetString(PyExc_TypeError, "必须传入列表类型参数");
                return NULL;
            }

            // 创建新的vector并填充数据
            std::vector<double>* vec = new std::vector<double>();
            const int list_size = PyList_Size(py_list);
            for (int i = 0; i < list_size; ++i) {
                PyObject* item = PyList_GetItem(py_list, i);
                if (!PyFloat_Check(item)) {
                    delete vec; // 提前清理避免内存泄漏
                    PyErr_SetString(PyExc_TypeError, "列表元素必须是浮点数");
                    return NULL;
                }
                vec->push_back(PyFloat_AsDouble(item));
            }

            // 创建C++对象
            SampleClass* instance = new SampleClass(vec);
            // 将vector与Python代理对象绑定,代理销毁时自动删除vector
            $module_attachptr(instance, vec, SWIGTYPE_p_std__vectorT_double_t);
            return instance;
        }
    }

    // 保留原有构造函数和方法声明
    SampleClass();
    void SampleMethod(std::vector<double>* arg);
    void SampleMethod2(std::vector<double>* arg);
    void print_member();
};

// 为成员方法保留原有的INPUT类型映射
%apply std::vector<double> *INPUT {std::vector<double>* arg};

优势

  • 无内存泄漏:当Python中的SampleClass实例被垃圾回收时,SWIG会自动销毁绑定的vector。
  • 输入校验:可以在构造函数中添加类型检查,提前抛出Python类型错误,避免C++端崩溃。
测试验证

修改后重新编译运行,Python端调用构造函数时:

import example as ex
b = ex.SampleClass([1.2, 3.1, 4.1])
print(b.m_v.size()) # 输出3,正常
b.print_member()    # 输出1.2 3.1 4.1,无段错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 06:01:38