使用std::unique_ptr处理new[]分配的指针,依赖默认删除器是否安全?
先直接给结论:如果你用对了unique_ptr的数组特化版本,那依赖这个默认删除器是安全的,但你的当前写法其实有问题,会触发未定义行为。
咱们一步步拆解:
你现在的代码是用
new uint8_t[binaryDataSize]分配了数组,然后把裸指针传给std::unique_ptr<uint8_t>。这里的核心问题是:std::unique_ptr<uint8_t>的默认删除器(std::default_delete<uint8_t>)会调用delete释放内存,但你是用new[]分配的内存,必须用delete[]释放——这种释放方式不匹配会导致未定义行为,比如内存泄漏、程序崩溃或者其他不可预期的错误。你贴出来的那个删除器代码,其实是
std::default_delete<T[]>的实现,也就是std::unique_ptr数组特化版本(std::unique_ptr<T[]>)的默认删除器。这个删除器专门针对数组场景设计:它明确调用delete[] __ptr完成释放,还通过静态断言确保_Tp不是不完全类型,避免了删除不完全类型指针的风险——用这个删除器释放new[]分配的数组是完全安全的。
那正确的写法应该是怎样的?有两种推荐方式:
- 直接使用数组特化的
unique_ptr:
std::unique_ptr<uint8_t[]> binPtr(new uint8_t[binaryDataSize]);
这时候unique_ptr会自动匹配你贴的数组版本默认删除器,释放时调用delete[],和new[]的分配逻辑完美匹配。
- 更符合现代C最佳实践的方式:用
std::make_unique(C14及以上支持):
auto binPtr = std::make_unique<uint8_t[]>(binaryDataSize);
这种写法不需要手动写new,避免了裸指针的使用,更贴合RAII思想,同时也会自动使用正确的数组删除器来释放内存。
总结一下:只要你用std::unique_ptr<T[]>(或者make_unique<T[]>)管理new[]分配的数组,依赖它的默认删除器就是完全安全的;但如果用std::unique_ptr<T>来管理数组,默认删除器会用错释放方式,存在严重风险。
内容的提问来源于stack exchange,提问作者toozyfuzzy

