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

C++中double free or corruption(out)问题的原因及修复咨询

分析并修复double free or corruption (out)错误(进程退出码134)

错误根源分析

你这里的问题很典型——你把栈上的局部对象地址交给了std::unique_ptr管理,而且还重复添加同一个地址到Data容器里。

仔细拆解你的代码问题点:

  • AccountsStruct accountsStruct;是LoadTable函数内的栈局部变量,整个循环过程中它的内存地址完全固定,每次循环只是覆盖修改它的成员值而已。
  • 调用Data.emplace_back(&accountsStruct)时,unique_ptr会接管这个栈对象的地址,但栈对象的生命周期由函数作用域管控,根本不属于堆内存范畴。当循环结束后,accountsStruct会被自动销毁,内存被系统回收。
  • 更致命的是,你每次循环都往Data里塞同一个地址,导致Data里的所有unique_ptr都指向同一块已经被标记为回收的栈内存。当Data(或者其中的unique_ptr)触发析构时,每个unique_ptr都会尝试释放这块内存,直接触发double free错误;另外,栈内存本来就不该由unique_ptr来释放,这种越界操作本身就会引发内存 corruption。

修复方案

你需要为每个账户创建独立的堆内存对象,让unique_ptr管理合法的堆内存。这里提供两种简洁的修复方式:

方式1:用std::make_unique直接构造堆对象(推荐)

如果你的项目支持C++14及以上,优先用std::make_unique,它比直接new更安全,能避免潜在的内存泄漏风险:

#include "Accounts.h"
using namespace Vibranium;
void Accounts::LoadTable(RowResult &res) {
    for (Row row : res.fetchAll()){
        // 直接在堆上构造AccountsStruct,make_unique会自动包装为unique_ptr
        Data.emplace_back(std::make_unique<AccountsStruct>(
            row[0].get<int>(),
            row[1].get<std::string>(),
            row[2].get<std::string>(),
            row[4].get<int>(),
            row[5].get<std::string>(),
            row[6].get<std::string>(),
            row[7].get<std::string>(),
            row[8].get<int>(),
            row[9].get<int>(),
            row[10].get<int>(),
            row[11].get<double>(),
            row[12].get<std::string>(),
            row[13].get<std::string>(),
            row[15].get<int>(),
            row[16].get<int>(),
            row[17].get<int>()
        ));
    }
    std::cout << "SIZE: " << Data.size() << std::endl;
}

注意:要确保参数顺序和AccountsStruct的构造函数参数(或成员变量顺序)完全匹配,如果结构体有默认构造函数,也可以用成员初始化列表的方式来写,可读性更强。

方式2:保留原有赋值逻辑,复制栈对象到堆

如果觉得直接构造参数太长可读性差,可以保留你原来的赋值逻辑,每次循环都创建新的堆对象:

#include "Accounts.h"
using namespace Vibranium;
void Accounts::LoadTable(RowResult &res) {
    for (Row row : res.fetchAll()){
        AccountsStruct accountsStruct;
        accountsStruct.id = row[0].get<int>();
        accountsStruct.email = row[1].get<std::string>();
        accountsStruct.warTag = row[2].get<std::string>();
        accountsStruct.state = row[4].get<int>();
        accountsStruct.name = row[5].get<std::string>();
        accountsStruct.lastname = row[6].get<std::string>();
        accountsStruct.country = row[7].get<std::string>();
        accountsStruct.dob_month = row[8].get<int>();
        accountsStruct.dob_day = row[9].get<int>();
        accountsStruct.dob_year = row[10].get<int>();
        accountsStruct.balance = row[11].get<double>();
        accountsStruct.created_at = row[12].get<std::string>();
        accountsStruct.updated_at = row[13].get<std::string>();
        accountsStruct.account_role = row[15].get<int>();
        accountsStruct.rank = row[16].get<int>();
        accountsStruct.playerRole = row[17].get<int>();
        // 把栈对象复制到堆内存,交给unique_ptr管理
        Data.emplace_back(std::make_unique<AccountsStruct>(accountsStruct));
    }
    std::cout << "SIZE: " << Data.size() << std::endl;
}

关键知识点回顾

  • std::unique_ptr的核心设计目标是管理堆内存,它会在生命周期结束时自动调用delete释放内存。如果给它传递栈对象的地址,delete栈内存是完全的未定义行为,必然会触发内存错误。
  • 栈局部变量的生命周期仅限于定义它的作用域(这里就是LoadTable函数内部),一旦离开作用域,内存就会被操作系统回收,后续再访问该地址都是非法的。

内容的提问来源于stack exchange,提问作者Venelin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 07:47:34