混用new char[]与unique_ptr<Config>的内存问题:是否泄漏?如何解决?
是否存在内存泄漏?
当前没有内存泄漏——Valgrind明确指出「All heap blocks were freed -- no leaks are possible」,说明分配的内存最终都被释放了。但你遇到的「Mismatched free() / delete / delete []」是更严重的未定义行为,虽然当前没泄漏,但在不同编译器、操作系统或运行环境下,可能出现内存泄漏、程序崩溃甚至更诡异的错误。
问题根源
你用new char[]分配了一块变长内存,却让std::unique_ptr<Config>用默认的delete操作符去释放。C++标准要求:new[]分配的内存必须用delete[]释放,new分配的必须用delete释放。默认的std::unique_ptr<T> deleter是delete,和new char[]完全不匹配,这就是Valgrind报错的原因。
至于释放时显示大小仅24字节:这是因为默认delete会根据Config的类型计算内存大小,sizeof(Config)刚好是24(5个uint32_t占20字节,加上末尾的unsigned char[1],内存对齐到4字节后总大小为24),但你实际分配的内存远大于这个值,这直接暴露了释放逻辑的不匹配。
解决方法
给std::unique_ptr指定自定义deleter,让它用delete[]释放内存,有两种简单实现方式:
方式1:用lambda作为deleter
static Config inited; std::unique_ptr<Config, void(*)(Config*)> ptr( reinterpret_cast<Config*>(new char[1 + inited._sizeof + dataLength]), [](Config* p) { // 把指针转回到char*,用delete[]释放 delete[] reinterpret_cast<char*>(p); } ); // 后续的memset、memcpy操作不变 memset(ptr.get(), 0, inited._sizeof + 100); memcpy(ptr.get(), &inited, sizeof(inited));
方式2:复用std::default_delete<char[]>
这种方式更简洁,直接利用标准库提供的deleter:
static Config inited; std::unique_ptr<Config, std::default_delete<char[]>> ptr( reinterpret_cast<Config*>(new char[1 + inited._sizeof + dataLength]) ); // 后续操作不变
std::default_delete<char[]>的逻辑就是调用delete[],完美匹配new char[]的分配逻辑。
这种用法是否属于常见实践?
你用的是C风格的柔性数组技巧(结构体末尾放unsigned char buffer[1],实际分配更长内存来存储变长数据),这种写法在C里比较常见,但在C中属于「遗留用法」——C有更安全的变长数据处理方式,比如std::vector<unsigned char>。
但如果因为结构体无法修改必须保留这种设计,那么配合自定义deleter的std::unique_ptr是比裸指针更安全的选择,属于合理的适配方案,不算非常规操作。
内容的提问来源于stack exchange,提问作者Digor

