c++protocol-bufferssmart-pointersdataformat

I want to write data in a protobuf format, but my program throws an exception


I'm having some problems when learning how to use protobuf data format with C++. And this is what i did.

  1. First,i constructed a protobuf structure and generate my header file.like this
syntax = "proto2";

package test;

message studentInfo {
    optional string id = 1;
    optional string name = 2;
    optional item3 favority = 3;
    optional int32 age = 4;
    optional item6 skills = 6;
}

message item3 {
    optional string name = 1;
}

message item6 {
    optional skillName skills = 4;
    optional skillslot size = 5;
}

message skillName {
    optional string skill1 = 1;
    optional string skill2 = 2;
}

message skillslot {
    optional int32 size = 1;
}

2.And then this is the code i wrote.

#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.c_str());

        //name
        stu.set_name(c_strName.c_str());

        //favority
        test::item3 itemFav;
        itemFav.set_name(c_strFav.c_str());
        stu.set_allocated_favority(&itemFav);

        //age
        stu.set_age(c_iAge);

        //skills
        test::skillName itemSkillList;
        itemSkillList.set_skill1(c_strSkill);
        itemSkillList.set_skill2(c_strSkill2);
        
        test::skillslot itemSlot;
        itemSlot.set_size(c_iSkillCount);

        test::item6 itemSkills;
        itemSkills.set_allocated_skills(&itemSkillList);
        itemSkills.set_allocated_size(&itemSlot);

        stu.set_allocated_skills(&itemSkills);

        //output
        {
            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;
}

3.Finally,it throws an exception when executing "delete skills_".

I guess because that variable is freed twice.So for try to solve this problem i wrote the following code.

#include "test.pb.h"
#include <memory>
#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;
    {
        std::shared_ptr<test::studentInfo> spStu(new test::studentInfo);
        //id
        spStu->set_id(c_strID.c_str());

        //name
        spStu->set_name(c_strName.c_str());

        //favority
        std::shared_ptr<test::item3> spFav(new test::item3);
        spFav->set_name(c_strFav.c_str());
        std::weak_ptr<test::item3> wpFav = spFav;
        spStu->set_allocated_favority(&*wpFav.lock());

        //age
        spStu->set_age(c_iAge);

        //skills
        std::shared_ptr<test::skillName> spSkillList(new test::skillName);
        spSkillList->set_skill1(c_strSkill);
        spSkillList->set_skill2(c_strSkill2);
        
        std::shared_ptr<test::skillslot> spSlot(new test::skillslot);
        spSlot->set_size(c_iSkillCount);

        std::shared_ptr<test::item6> spSkills(new test::item6);
        std::weak_ptr<test::skillName> wpSkillList = spSkillList;
        std::weak_ptr<test::skillslot> wpspSlot = spSlot;
        spSkills->set_allocated_skills(&*wpSkillList.lock());
        spSkills->set_allocated_size(&*wpspSlot.lock());

        std::weak_ptr<test::item6> wpSkills = spSkills;
        spStu->set_allocated_skills(&*wpSkills.lock());

        //output
        {
            std::fstream output(c_strPath, std::ios::out | std::ios::trunc | std::ios::binary);
            if (output.is_open())
            {
                spStu->SerializePartialToOstream(&output);
                output.close();
            }
        }
        google::protobuf::ShutdownProtobufLibrary();
    }
}

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

As the title says,It still crashes.
enter image description here I am not sure what the problem is and what should I do to solve this prolem, hope someone can tell me...T^T


Solution

  • Thanks@ molbdnilo
    Now I can write code that doesn't throw exceptions.

    void RunPBTest()
    {
    GOOGLE_PROTOBUF_VERSION;
    {
        test::studentInfo pStu;
        test::item3* pFav = pStu.mutable_favority();
        test::item6* pSkills = pStu.mutable_skills();
        test::skillName* pSkillList = pSkills->mutable_skills();
        test::skillslot* pSkillSlot = pSkills->mutable_size();
    
        pStu.set_id(c_strID.c_str());
        pStu.set_name(c_strName.c_str());
        pFav->set_name(c_strFav.c_str());
        pStu.set_age(c_iAge);
        pSkillList->set_skill1(c_strSkill);
        pSkillList->set_skill2(c_strSkill2);
        pSkillSlot->set_size(c_iSkillCount);
    
        //output
        {
            std::fstream output(c_strPath, std::ios::out | std::ios::trunc | std::ios::binary);
            if (output.is_open())
            {
                pStu.SerializePartialToOstream(&output);
                output.close();
            }
        }
        google::protobuf::ShutdownProtobufLibrary();
    }
    

    }