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
相关产品推荐
相关产品推荐

