C++中修改OpenCV cv::Mat类对象的data指针是否可行?
直接修改cv::Mat的data指针的风险及最优实现方案
现有代码的合法性与安全隐患
你这段直接修改cv::Mat的data指针的操作不符合OpenCV的API设计规范,当前运行没有问题属于巧合,存在多个严重安全隐患:
- 内存泄漏风险:调用
new_mat.create(20, 100, CV_8UC3)时OpenCV已经为该实例分配了对应大小的堆内存,直接修改data指针会导致原有分配的内存失去引用,永远无法被释放,程序长时间运行会出现内存持续上涨的问题。 - 内存释放异常:
cv::Mat通过内部引用计数和释放器管理内存生命周期,你手动将data指向栈上分配的arr数组,当new_mat析构时,OpenCV会尝试调用释放器释放data指向的地址,而栈内存无法被free/delete释放,会直接触发未定义行为,大概率导致程序崩溃,你当前未遇到问题多数是测试场景下程序提前退出,未触发析构的释放逻辑。 - 生命周期错配风险:当前示例中
arr如果是局部栈变量,一旦new_mat的生命周期长于arr,new_mat的data会变成野指针,访问时直接触发段错误。 - 引用计数逻辑混乱:手动修改
data指针后,cv::Mat的裁剪、拷贝、ROI操作都会因为内部元数据和实际指向内存不匹配出现不可预期的错误。
零拷贝的合法实现方案
你想要避免深拷贝的需求完全可以通过OpenCV官方支持的外部内存包装接口实现,性能和你手动改指针完全一致,没有任何额外开销,示例代码如下:
unsigned char arr[100*3*20] = { 0, }; // 直接构造Mat包装外部内存,不会执行深拷贝 cv::Mat new_mat(20, 100, CV_8UC3, arr); // 如果你的数组行步长和OpenCV默认步长不一致,可传入第五个参数显式指定 // cv::Mat new_mat(20, 100, CV_8UC3, arr, custom_step);
该方案的优势:
- 符合OpenCV API规范,通过该方式构造的
cv::Mat内部释放器为空,析构时不会尝试释放你传入的外部内存,不会出现内存释放异常的问题 - 全程无内存拷贝,性能和你原有修改指针的写法完全一致,满足高性能场景要求
- 仅需要你自行保证
arr的生命周期长于所有引用该内存的cv::Mat实例即可,没有其他额外限制 - 如果后续需要独立修改
new_mat且不影响原数组,再调用new_mat.clone()执行深拷贝即可,灵活适配不同场景需求。
内容的提问来源于stack exchange,提问作者Seongkyun Han
相关产品推荐
相关产品推荐

