用C++中的BOOST序列化循环图

Serialize cyclic graphs with BOOST in C++

本文关键字:循环 序列化 BOOST C++ 中的      更新时间:2023-10-16

我将基本代码块和它们之间的控制流表示为循环图,并希望能够将图序列化为XML或类似内容,然后对其进行反序列化,并在另一个应用程序中使用该图。当试图序列化数据结构时,我会得到数千次对序列化函数的调用,即使我用来测试应用程序的图包含的节点不到50个,这让我相信循环引用存在问题。

当我运行或调试应用程序时,它成功地重复进入void serialize(Archive&, std::vector<BasicBlock*>&, const unsigned)函数,直到它因分段故障而崩溃。输出文件已创建,但未写入任何内容。

以下是我用来表示基本块的数据结构;

struct __attribute__ ((visibility ("default"))) BasicBlock {
    unsigned int id;
    unsigned int start_address;
    unsigned int end_address;
    std::vector<BasicBlock*>* outgoing;
    std::vector<BasicBlock*>* incoming;
};

这就是序列化类和函数

class Serialize {
public:
    static void marshal(const std::vector<BasicBlock*>& basic_blocks, std::string filename) {
        std::ofstream ofstream(filename.c_str(), std::ios::out | std::ios::binary);
        boost::archive::text_oarchive archive(ofstream);
        archive << basic_blocks;
    }
    static void unmarshal(const std::string filename, std::vector<BasicBlock*>& basic_blocks) {
        std::ifstream ifstream(filename.c_str());
        boost::archive::text_iarchive archive(ifstream);
        archive >> basic_blocks;
    }
};
namespace boost {
    namespace serialization {
    template<class Archive>
    void save(Archive & archive, const BasicBlock& basic_block, const unsigned int version) {
        archive & basic_block.id;
        archive & basic_block.start_address;
        archive & basic_block.end_address;
        archive & basic_block.incoming;
        archive & basic_block.outgoing;
    }
    template<class Archive>
    void load(Archive & archive, BasicBlock& basic_block, const unsigned int version) {
        archive & basic_block.id;
        archive & basic_block.start_address;
        archive & basic_block.end_address;
        archive & basic_block.incoming;
        archive & basic_block.outgoing;
    }
    template<typename Archive>
    void serialize(Archive& archive, std::vector<BasicBlock>& basic_blocks, const unsigned version) {
        archive & basic_blocks;
    }
    template<typename Archive>
    void serialize(Archive& archive, std::vector<BasicBlock*>& basic_blocks, const unsigned version) {
        archive & basic_blocks; // Triggered thousands of times...
    }
    }
}
BOOST_SERIALIZATION_SPLIT_FREE(BasicBlock)

我的第一个怀疑是,vector的"保存"重载实际上会毁掉你的一切。

template<typename Archive>
    void serialize(Archive& archive, std::vector<BasicBlock*>& basic_blocks, const unsigned version) {
        archive & basic_blocks; // Triggered thousands of times...
    }

会。。。(间接地)递归地称自己为AFAICT

你试过包括boost/serialization/vector.hpp吗?

这里有一个SSCCE显示它是有效的:在Coliru上查看它

#include <boost/serialization/vector.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <vector>
#include <fstream>
struct BasicBlock {
    unsigned int id;
    unsigned int start_address;
    unsigned int end_address;
    std::vector<BasicBlock*>* outgoing;
    std::vector<BasicBlock*>* incoming;
};
// BOOST_CLASS_TRACKING(BasicBlock, boost::serialization::track_always)
namespace boost {
    namespace serialization {
        template<class Archive>
            void save(Archive & archive, const BasicBlock& basic_block, const unsigned int version) {
                archive & basic_block.id;
                archive & basic_block.start_address;
                archive & basic_block.end_address;
                archive & basic_block.incoming;
                archive & basic_block.outgoing;
            }
        template<class Archive>
            void load(Archive & archive, BasicBlock& basic_block, const unsigned int version) {
                archive & basic_block.id;
                archive & basic_block.start_address;
                archive & basic_block.end_address;
                archive & basic_block.incoming;
                archive & basic_block.outgoing;
            }
    }
}
BOOST_SERIALIZATION_SPLIT_FREE(BasicBlock)
int main()
{
    BasicBlock root
    {
        1, 2, 3,
        new std::vector<BasicBlock*> { new BasicBlock { 4, 5, 6, nullptr, nullptr } },
        new std::vector<BasicBlock*> { &root } // cyclic!
    };
    boost::archive::text_oarchive ar(std::cout);
    ar << root;
    // everything leaked :)
}