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

C++使用Protobuf写入数据时触发重复释放崩溃问题求助

问题根源分析

你的崩溃核心原因是Protobuf的set_allocated_xxx方法的所有权规则理解错误:

  • set_allocated_xxx(T* ptr)会让Protobuf消息对象接管ptr的所有权,当消息对象析构时,会自动delete ptr。
  • 第一个版本中,你传入的是栈上局部对象的地址,当局部对象离开作用域自动析构后,Protobuf后续再delete这个地址,就会触发非法内存访问/重复释放。
  • 第二个版本用智能指针时,智能指针和Protobuf同时管理同一个指针的所有权,两者都会尝试delete,依然导致双重释放。
正确解决方案

推荐优先使用Protobuf提供的mutable_xxx()方法,它会直接返回内部嵌套对象的引用/指针,所有权完全由Protobuf管理,无需手动处理内存。

修改后的代码(推荐方式)

#include "test.pb.h"
#include <fstream>

#pragma comment(lib,"libprotoc.lib")
#pragma comment(lib,"libprotobuf.lib")

const std::string c_strID = "555222333";
const std::string c_strName = "cat";
const std::string c_strFav = "Apple";
const std::string c_strSkill = "Sleep";
const std::string c_strSkill2 = "Eat";
constexpr int c_iAge = 21;
constexpr int c_iSkillCount = 2;

const std::string c_strPath = "D:\\test.txt";

void RunPBTest()
{
    GOOGLE_PROTOBUF_VERSION;
    {
        test::studentInfo stu;
        // id
        stu.set_id(c_strID);
        // name
        stu.set_name(c_strName);
        // favority:用mutable_获取内部对象,直接修改
        test::item3* itemFav = stu.mutable_favority();
        itemFav->set_name(c_strFav);
        // age
        stu.set_age(c_iAge);
        // skills:逐层获取嵌套对象
        test::item6* itemSkills = stu.mutable_skills();
        test::skillName* skillList = itemSkills->mutable_skills();
        skillList->set_skill1(c_strSkill);
        skillList->set_skill2(c_strSkill2);
        
        test::skillslot* slot = itemSkills->mutable_size();
        slot->set_size(c_iSkillCount);

        // 序列化输出
        std::fstream output(c_strPath, std::ios::out | std::ios::trunc | std::ios::binary);
        if (output.is_open())
        {
            stu.SerializePartialToOstream(&output);
            output.close();
        }
        google::protobuf::ShutdownProtobufLibrary();
    }
}

int main()
{
    RunPBTest();
    return 0;
}

若必须使用set_allocated_xxx的处理方式(不推荐)

如果你因为某些场景必须手动分配对象,需要传递堆上new的对象,且不能让其他智能指针管理这个对象的所有权:

// 示例:favority的处理
test::item3* itemFav = new test::item3();
itemFav->set_name(c_strFav);
stu.set_allocated_favority(itemFav); // Protobuf会接管这个指针,析构时自动delete

// 注意:不要用智能指针包裹itemFav,否则智能指针和Protobuf会双重释放

或者用智能指针的release()方法释放所有权:

std::unique_ptr<test::item3> spFav(new test::item3());
spFav->set_name(c_strFav);
stu.set_allocated_favority(spFav.release()); // 释放所有权给Protobuf
关键注意事项
  • 永远不要给set_allocated_xxx传递栈对象的地址,这会导致栈对象销毁后Protobuf重复释放。
  • 不要同时让智能指针和Protobuf管理同一个对象的所有权,必须明确唯一的所有者。
  • mutable_xxx()是Protobuf推荐的嵌套对象操作方式,内存安全且代码更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 17:50:24