C++20递归与循环场景下的内存管理问题
你的问题根源很明确:原代码中生成new_arr后,将它传给三个递归调用,每个子调用都会delete这个传入的指针,三次释放同一块内存直接触发double free;但如果不释放old_arr,每一层递归都新分配数组,深度15的三叉树会导致内存占用急剧膨胀。
可行方案
方案1:用shared_ptr自动管理数组(推荐)
你之前尝试shared_ptr失败,核心错误是没处理数组的释放逻辑——默认shared_ptr用delete而非delete[]清理内存,会引发未定义行为。正确的做法是使用支持数组的shared_ptr:
C++17及以后可直接用std::shared_ptr<int[]>,它默认适配delete[];更早的标准需要手动指定删除器。调整后的代码如下:
#include <memory> void routine(std::shared_ptr<int[]> old_arr, int k, int depth) { if (depth == 15) return; // C++17+ 写法 std::shared_ptr<int[]> new_arr(new int[size]); // C++17之前写法:std::shared_ptr<int[]> new_arr(new int[size], std::default_delete<int[]>()); // 基于old_arr构建new_arr的操作 for (int i = 0; i < 3; i++) { routine(new_arr, k, depth + 1); } // 无需手动释放任何指针: // new_arr的引用计数会随子调用增减,所有拷贝销毁时自动释放内存;old_arr也会在当前函数结束后自动清理 }
这个方案靠shared_ptr的引用计数机制解决问题:每次传递new_arr给子调用,引用计数加1;子调用结束后拷贝销毁,计数减1。只有当所有子调用完成、当前函数的new_arr也销毁时,计数归零,内存才会被释放,完美避免double free和内存泄漏。
方案2:手动延迟释放new_arr
如果不想用智能指针,可调整释放时机:当前层生成new_arr后先释放old_arr(它已完成使命),等所有子递归调用全部结束后,再释放new_arr。注意:子递归函数里绝对不能再释放传入的指针!
代码结构如下:
void routine(int* old_arr, int k, int depth) { if (depth == 15) { delete[] old_arr; // 最后一层释放传入的数组 return; } int* new_arr = new int[size]; // 基于old_arr构建new_arr的操作 delete[] old_arr; // 释放已无用的old_arr for (int i = 0; i < 3; i++) { routine(new_arr, k, depth + 1); } delete[] new_arr; // 所有子递归执行完毕,释放new_arr return; }
这个方案有个严格前提:子递归过程中不能修改new_arr的内容,否则三个子调用共享同一块内存会导致数据混乱。如果你的逻辑里new_arr是只读的,这个方案可行;若需要修改,还是得用智能指针或者为每个子调用拷贝数组(但会增加内存占用)。
你之前的shared_ptr尝试为什么不可行?
你手动判断use_count()并调用reset()属于画蛇添足,更关键的错误是没使用数组版本的shared_ptr,导致释放时用了错误的delete而非delete[],不仅解决不了问题,还会引发新的内存错误。
内容的提问来源于stack exchange,提问作者Boots

