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

C++中返回Ort::Value导致std::vector与shape值异常变更的修复

问题修复:ONNX Runtime创建Tensor时局部变量生命周期导致的异常

问题描述

封装i2t函数创建ONNX Tensor时,返回Ort::Value后input_vector和input_shape的值出现异常变更;直接在测试函数内编写相同逻辑则正常,最终导致推理结果错误。

核心原因

问题出在局部变量的生命周期不匹配:

  • 在i2t函数中,input_img是局部变量,input_vector和input_shape依赖于它的内部数据。
  • Ort::Value::CreateTensor若使用用户提供的内存,不会接管内存所有权,仅保持引用。函数返回后,局部变量input_img被销毁,其内部的data和shape内存被释放,导致Tensor持有野指针,后续访问出现值异常。
  • 直接在测试函数内编写时,input_img的生命周期覆盖了Tensor的使用周期,因此无问题。

修复方案

方案1:让ONNX Runtime接管内存分配

修改i2t函数,让Tensor使用ONNX Runtime的分配器创建并拷贝数据,使Tensor拥有内存所有权,不受局部变量销毁影响:

Ort::Value i2t(const std::string &img_path) {
    Ndarray<float> input_img = i2t2(img_path);
    auto input_shape = input_img.shape;
    size_t tensor_size = input_img.data.size();

    // 创建ONNX Runtime内存分配器信息
    auto mem_info = Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault);
    // 创建空Tensor,由ONNX Runtime分配内存
    Ort::Value tensor = Ort::Value::CreateTensor<float>(
        mem_info,
        tensor_size,
        input_shape.data(),
        input_shape.size()
    );

    // 将预处理后的数据拷贝到Tensor内存中
    std::copy(input_img.data.begin(), input_img.data.end(), tensor.GetTensorMutableData<float>());
    return tensor;
}

方案2:延长输入数据的生命周期

将input_img的生命周期延长到Tensor使用结束,修改i2t函数接受已存在的Ndarray引用:

// 修改i2t函数,接收外部传入的Ndarray引用
Ort::Value i2t(const Ndarray<float>& input_img) {
    auto input_vector = input_img.data;
    auto input_shape = input_img.shape;
    auto mem_info = Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault);
    return Ort::Value::CreateTensor<float>(
        mem_info,
        input_vector.data(),
        input_vector.size(),
        input_shape.data(),
        input_shape.size()
    );
}

// 在测试函数中调用
TEST_F(OnnxTest, run_onnx) {
    // ... 路径定义等代码 ...
    Ndarray<float> input_img = i2t2(input_img_path);
    auto tensor = i2t(input_img); // input_img生命周期覆盖tensor的使用周期
    // ... 推理及后续代码 ...
}

额外注意事项

  • 检查Ndarray类实现:确保data(如std::vector<float>)和shape的内存管理正确,避免浅拷贝导致的野指针问题。
  • 原代码中i2t函数的mem_info未定义,属于语法错误,必须在函数内创建正确的Ort::MemoryInfo实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 20:13:12