本文介绍了无法存档所有数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用boost对数据进行序列化.

I am using boost for serialization of data.

这是类的结构.

1)我有一个舞台班此类保存导演类的矢量数据

1) I have a Stage classThis class holds vector data for the director class

class Stage
{
public:
    std::vector<Director> directors;
    void AddDirector(Director dir) { directors.push_back(dir); }
    int GetDirectorSize() { return directors.size(); }
    Director* GetDirector(int number) { return &directors[number]; }

private:
    friend class boost::serialization::access;
    template<typename Archive>
    void save(Archive& ar, const unsigned int version) const {
        ar & directors;
    }
    template<typename Archive>
    void load(Archive& ar, const unsigned int version) {
        ar & directors;
    }
    BOOST_SERIALIZATION_SPLIT_MEMBER()
};

2)这是导演班此类包含通道类的弱指针的矢量数据.

2) This is the director classThis class holds vector data of weak pointers for the channel class.

class Director
{
public:
    std::string stdstrName;
    std::vector<std::weak_ptr<Channel>> channels;
    Director() { stdstrName = "NO_NAME"; }
    void SetName(std::string name) { stdstrName = name; }
    std::string GetName() { return stdstrName; }
    void AddChannel(std::weak_ptr<Channel> chn) { channels.push_back(chn); }
    std::shared_ptr<Channel> GetChannel(int number) { return channels[number].lock(); }
    int GetChannelSize() {return channels.size();}
    std::string GetChannelType( int number){
        if (std::shared_ptr<Channel> chn = channels[number].lock())
            return chn->GetChannelType();
    }

private:
    friend class boost::serialization::access;
    template<typename Archive>
    void save(Archive& ar, const unsigned int version) const {
        ar & stdstrName & channels;
    }
    template<typename Archive>
    void load(Archive& ar, const unsigned int version) {
        ar & stdstrName & channels;
    }
    BOOST_SERIALIZATION_SPLIT_MEMBER()

};

3)这是频道类别

Channel类需要了解创建容器的位置以及存储为Weak_pointer的控制器

Channel class needs to know about the container where it is created and thedirector where this is stored as a Weak_pointer

1)此类包含指向Director对象的指针.

1) This class holds a pointer to the Director object.

2)此类包含指向Container对象的指针.

2) This class holds a pointer to the Container object.

class Container;
class Director;

class Channel
{
public:
    Director* dir;
    Container* cont;
    std::string stdstrChannelType;
    Channel() { stdstrChannelType = "NO_TYPE"; }
    Channel(std::string type): stdstrChannelType(type){  }
    void SetDirector(Director* director);
    void SetContainer(Container* container);
    std::string GetChannelType() { return  stdstrChannelType;}
    Director* GetDirector() { return dir; }

private:
    friend class boost::serialization::access;
    template<typename Archive>
    void save(Archive& ar, const unsigned int version) const {
        ar & dir & cont & stdstrChannelType;
    }
    template<typename Archive>
    void load(Archive& ar, const unsigned int version) {
        ar & dir & cont & stdstrChannelType;
    }
    BOOST_SERIALIZATION_SPLIT_MEMBER()

};

////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////

 #include "Channel.h"
#include <vector>

class PositionChannel : public Channel
{
public:
    std::vector<int> keyframes;
    PositionChannel() : Channel("POSITION") , keyframes( { 1 , 2, 3 }) {    }

   private:
   friend class boost::serialization::access;

typedef Channel _Super;
template<typename Archive>
void save(Archive& ar, const unsigned int version) const {
    ar & boost::serialization::base_object<_Super>(*this);
    ar & keyframes;
}
template<typename Archive>
void load(Archive& ar, const unsigned int version) {
    ar & keyframes;
}
BOOST_SERIALIZATION_SPLIT_MEMBER()

};

4)这是容器类

1)在此处创建通道并将其另存为Shared_pointer.

1) This is where the Channel is created and saved as a Shared_pointer.

2)相同的频道也作为Weak_Pointer保存在Director类中.

2) The same channel is also saved in the Director class as Weak_Pointer

class Container
{
public:
    std::string stdstrName;
    std::vector<std::shared_ptr<Channel>> channel;
    Container() { stdstrName = "cont"; };
    void AddChannel(std::shared_ptr<Channel> chn)
    {
        channel.push_back(chn);
        Director* dir = chn->GetDirector();  // Add the channel to director also
        dir->AddChannel(chn);
    }

private:
    friend class boost::serialization::access;
    template<typename Archive>
    void save(Archive& ar, const unsigned int version) const {
        ar & stdstrName & channel;
    }
    template<typename Archive>
    void load(Archive& ar, const unsigned int version) {
        ar & stdstrName & channel;
    }
    BOOST_SERIALIZATION_SPLIT_MEMBER()

};

现在,当我序列化我的数据并比序列化它时,Director无法序列化weak_pointer.

Now when i serialize my data and than serialize it the Director is not able to serialize the weak_pointer.

Stage stage;
Director dir;
Container cont;
dir.SetName("MAIN");
stage.AddDirector(dir); // Add director to stage
std::shared_ptr<PositionChannel> chn = std::make_shared<PositionChannel>(PositionChannel()); // create a position channel
chn->SetDirector(&dir); // Link the director to channel
chn->SetContainer(&cont); // Link the container to the channel
cont.AddChannel(chn);   // add the channel to the container
std::cout << dir.GetChannelSize() << std::endl; // this gives a value of 1 which is correct
std::ofstream ofs("D://abc.dat");
{
    boost::archive::text_oarchive oa(ofs);
    // write class instance to archive
    oa << stage <<  cont;  // since director is a data element of stage so it should get serialized
}
Stage stage1;
Container cont1;
{
    // create and open an archive for input
    std::ifstream ifs("D://abc.dat");
    boost::archive::text_iarchive ia(ifs);
    // read class state from archive
    ia >> stage1 >> cont1;

}
std::cout << stage1.GetDirectorSize(); // stage has got the director
Director* dir1 = stage1.GetDirector(0);
std::cout << dir1->GetName(); // the director has the correct name
std::cout << dir1->GetChannelSize(); // it should show 1 as the channel size but i am getting 0

推荐答案

执行时

stage.AddDirector(dir); // Add director to stage

它将dir副本添加到stage :: directors`向量.

It adds a copy of dir to the stage::directors` vector.

您以后做

chn->SetDirector(&dir); // Link the director to channel

这意味着您将变量指向main.这与推上舞台的人不同.这可能不是您想要的.

This means you point the the variable in main. Which was different from the one pushed into the stage. This is likely not what you wanted.

chn->cont = &cont;

设置指向cont的指针,该指针也是,只是main范围内的变量.最大的区别是该确切的对象已序列化到存档中,因此,如果存档中找到指向该对象的指针,则可以正确地建立链接.

sets a pointer to cont, which is also just a variable in the scope of main. The big difference is that that exact object IS serialized into the archive, so if the archive finds pointers pointing to it it can make the link correctly.

第一次通过指针对对象进行反序列化时,就不能再通过引用对对象进行反序列化(因为指向的对象已被动态分配).

When an object is first deserialized through a pointer it can no longer be deserialized through a reference (because the pointed-to object has already been dynamically allocated).

有关更多背景信息,请参见: http://www .bnikolic.co.uk/blog/cpp-boost-ser-conflict.html

See for more background inforation: http://www.bnikolic.co.uk/blog/cpp-boost-ser-conflict.html

在您的情况下,您有如此多的循环依赖关系,没有顺序可以序列化stagecont,因此不会导致指针冲突.

In your case you have so many cyclic dependencies going on, there is no order in which you can serialize stage and cont so it doesn't lead to pointer conflict.

解决问题的最简单方法是将vector<Director>转换为vector<shared_ptr<Director> >.然后,您仍然必须确保在stage之前先序列化cont.

The easiest way to break the problem is to make vector<Director> into vector<shared_ptr<Director> >. Then you still have to make sure that cont is serialized before stage.

这是一个可行的简化演示:

Here's a simplified demo that works:

在Coliru上直播

Live On Coliru

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/weak_ptr.hpp>
#include <boost/serialization/export.hpp>
#include <fstream>

namespace Lib {
    struct Container;
    struct Director;

    struct Channel {
        Director* dir = nullptr;
        Container* cont = nullptr;
        virtual ~Channel() = default;
    };
    struct PositionChannel : Channel {
        std::vector<int> keyframes;
    };
    struct Director {
        std::string name;
        std::vector<std::weak_ptr<Channel>> channels;
    };
    struct Stage {
        std::vector<std::shared_ptr<Director> > directors;
    };
    struct Container {
        std::vector<std::shared_ptr<Channel> > channels;
    };

    template <typename Ar> void serialize(Ar& ar, Channel& o, unsigned) {
        //ar & o.dir & o.cont; // avoid pointer conflict
        ar & o.cont & o.dir;
    }
    template <typename Ar> void serialize(Ar& ar, PositionChannel& o, unsigned) {
        ar & boost::serialization::base_object<Channel>(o)
           & o.keyframes;
    }
    template <typename Ar> void serialize(Ar& ar, Director& o, unsigned) {
        ar & o.name & o.channels;
    }
    template <typename Ar> void serialize(Ar& ar, Stage& o, unsigned) {
        ar & o.directors;
    }
    template <typename Ar> void serialize(Ar& ar, Container& o, unsigned) {
        ar & o.channels;
    }
}

BOOST_CLASS_EXPORT(Lib::Channel)
BOOST_CLASS_EXPORT(Lib::PositionChannel)

int main() {
    using namespace Lib;
    {
        Stage stage;
        Container cont;

        auto dir = std::make_shared<Director>();
        dir->name = "MAIN";
        stage.directors.push_back(dir); // Add director to stage

        auto chn = std::make_shared<PositionChannel>(PositionChannel()); // create a position channel
        chn->dir = dir.get();
        chn->cont = &cont;

        dir->channels.emplace_back(chn); // add the weak ptr

        cont.channels.insert(cont.channels.end(),
            {
                chn,
                std::make_shared<PositionChannel>(),
                std::make_shared<PositionChannel>(),
                std::make_shared<PositionChannel>(),
            });

        {
            std::ofstream ofs("abc.dat");
            boost::archive::text_oarchive oa(ofs);
            //oa << stage << cont;
            oa << cont << stage;
        }
    }

    {
        std::ifstream ifs("abc.dat");
        boost::archive::text_iarchive ia(ifs);
        Stage stage;
        Container cont;

        //ia >> stage >> cont;
        ia >> cont >> stage;

        assert(cont.channels.size() == 4);

        auto chn = cont.channels.front();
        assert(chn == chn->dir->channels.front().lock());
        assert(chn->cont == &cont);
    }
}

传递所有断言并编写一个包含以下内容的文本存档:

Which passes all the asserts and writes a text archive containing:

22 serialization::archive 17 1 0
0 0 0 4 1 0 1 4 20 Lib::PositionChannel 1 0
1 1 0
2 0 0 5 1 0
3 4 MAIN 0 0 1 0 0 0 4 1 0 0 4
4
5 -1 -1 0 0 4
6
7 -1 -1 0 0 4
8
9 -1 -1 0 0 0 0 0 0 1 1 0 1 5 3

这篇关于无法存档所有数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

05-29 04:06
查看更多