You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 17:03:18