我正在使用boost进行数据序列化。
这就是类的结构。
1)我有一个舞台课
此类保存导演类的 vector 数据
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)这是导演类
此类保存通道类的弱指针的 vector 数据。
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的Director
1)此类包含指向Director对象的指针。
2)此类包含指向Container对象的指针。
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。
2)同一通道也作为Weak_Pointer保存在Director类中
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。
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` vector 中。以后你做
chn->SetDirector(&dir); // Link the director to channel
这意味着您将变量指向
main
。这与推上舞台的人不同。这可能不是您想要的。比较:
chn->cont = &cont;
设置一个指向
cont
的指针,它是,也是,只是main
范围内的一个变量。最大的区别是确切的对象已序列化到存档中,因此,如果存档中找到指向它的指针,则可以正确地建立链接。指针冲突
当首先通过指针对对象进行反序列化时,无法再通过引用对其进行反序列化(因为指向的对象已被动态分配)。
请参阅更多背景信息:http://www.bnikolic.co.uk/blog/cpp-boost-ser-conflict.html
在您的情况下,您有如此多的循环依赖关系,没有序列化
stage
和cont
的顺序,因此不会导致指针冲突。解决该问题的最简单方法是将
vector<Director>
变成vector<shared_ptr<Director> >
。然后,您仍然必须确保cont
在stage
之前已序列化。固定演示
这是一个可行的简化演示:
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);
}
}
它传递所有断言并编写包含以下内容的文本存档:
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