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
相关产品推荐
相关产品推荐

