堆上用new分配数组后赋值给shared_ptr,如何释放T* blob数据?
在DNA_ImageBlob类中,通过new[]分配了一块T类型的数组,随后将该数组指针赋值给std::shared_ptr<T>类型的成员data_,需要确保这块内存被正确释放。
现有代码问题分析
先看当前的实现代码:
DNA_ImageBlob::Reset方法
template <class T> void DNA_ImageBlob<T>::Reset(int h, int w, int c) { SetWidth(w); SetHeight(h); SetDepth(c); T *blob = alocData(h, w, c); data_ = std::make_shared<T>(blob); // 错误:此处会导致内存释放异常 compressed_ = false; }
alocData方法
template <class T> T *DNA_ImageBlob<T>::alocData(unsigned int h, unsigned int w, unsigned int d) { if (w * h * d == 0) { return nullptr; } T *blob = new T[w * h * d]; // 使用new[]分配数组 return blob; }
DNA_Mask构造函数示例
DNA_Mask::DNA_Mask(int id, int xSize, int ySize, int zSize) : DNA_BinaryImageBlob(xSize, ySize, zSize) { mID = id; height_ = xSize; width_ = ySize; depth_ = zSize; data_ = std::shared_ptr<BinaryType>(this->alocData(height_, width_, depth_)); // 同样存在释放错误 }
当前代码的核心问题:
alocData用new[]分配数组,但std::shared_ptr默认的删除器是调用delete,而非delete[],这会导致未定义行为(内存泄漏、程序崩溃等)。std::make_shared<T>(blob)的用法完全错误:它会把blob当作单个T对象的指针来构造shared_ptr,实际blob是数组首地址,这不仅会导致释放方式错误,还会在构造时错误地解引用数组指针(如果T有构造函数的话)。
正确的解决方案
方案1:给std::shared_ptr指定自定义删除器
既然用new[]分配数组,就必须用delete[]释放,因此需要给shared_ptr传入一个自定义删除器,告诉它用delete[]来清理内存。
修改Reset方法:
template <class T> void DNA_ImageBlob<T>::Reset(int h, int w, int c) { SetWidth(w); SetHeight(h); SetDepth(c); T *blob = alocData(h, w, c); // 传入lambda作为删除器,使用delete[]释放数组 data_ = std::shared_ptr<T>(blob, [](T* ptr) { delete[] ptr; }); compressed_ = false; }
修改DNA_Mask构造函数:
DNA_Mask::DNA_Mask(int id, int xSize, int ySize, int zSize) : DNA_BinaryImageBlob(xSize, ySize, zSize) { mID = id; height_ = xSize; width_ = ySize; depth_ = zSize; BinaryType* blob = this->alocData(height_, width_, depth_); data_ = std::shared_ptr<BinaryType>(blob, [](BinaryType* ptr) { delete[] ptr; }); }
方案2:用std::vector<T>替代手动内存管理(更推荐)
手动分配数组并配合shared_ptr容易出错,更安全的做法是用std::vector<T>来管理数组内存,它会自动调用delete[]释放内存,同时可以通过data()方法获取底层数组指针,完全兼容现有逻辑。
可以将data_的类型从std::shared_ptr<T>改为std::shared_ptr<std::vector<T>>,或者直接用std::vector<T>(如果不需要跨对象共享所有权的话)。
修改示例:
// 调整DNA_ImageBlob的成员类型 template <class T> class DNA_ImageBlob { private: std::shared_ptr<std::vector<T>> data_; // ...其他成员 }; template <class T> void DNA_ImageBlob<T>::Reset(int h, int w, int c) { SetWidth(w); SetHeight(h); SetDepth(c); size_t total = static_cast<size_t>(h) * w * c; data_ = std::make_shared<std::vector<T>>(total); // vector自动分配内存 compressed_ = false; } // 获取底层数组指针的方法(如果需要对外提供) template <class T> T* DNA_ImageBlob<T>::GetData() { return data_->data(); }
这种方式的优势:
- 完全避免手动内存管理的错误,vector自动处理内存分配和释放。
- 支持动态调整大小,自带边界检查(如果使用
at()访问的话),更安全。 shared_ptr<std::vector<T>>可以方便地在多个对象间共享数组所有权。
内容的提问来源于stack exchange,提问作者Andre Ahmed
相关产品推荐
相关产品推荐

