gpt4 book ai didi

c++ - 使用 boost::serialization 将派生类指针序列化为 vector 的问题

转载 作者:太空狗 更新时间:2023-10-29 22:54:11 25 4
gpt4 key购买 nike

我有一段代码,其中定义了以下类:Base , Derived , Contaienr .

Derived明显继承Base , 而 Container包含 Base 的 vector 共享指针,可以是 Base 的指针和 Derived .

我要连载Container所以 vector 的元素被序列化为 BaseDerived尊敬的,但它似乎不起作用。

这是我的测试代码:

#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/export.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <sstream>

/// Base class ///
class Base {
public:

using Ptr = std::shared_ptr<Base>;

public:

void setDouble(double d) {
m_d = d;
}

void setInteger(int c) {
m_c = c;
}

double getDouble() const {
return m_d;
}

int getInteger() const {
return m_c;
}

private:

double m_d;
int m_c;
};

/// Derived class from Base ///
class Derived : public Base {
public:

using Ptr = std::shared_ptr<Derived>;

public:

void setString(const std::string& s) {
m_s = s;
}

const std::string& getString() const {
return m_s;
}

private:

std::string m_s;
};

/// Container of base class pointers ///
class Container {
public:

void addData(Base::Ptr data) {
m_data.push_back(data);
}

const std::vector<Base::Ptr>& getDataVector() const {
return m_data;
}

private:

std::vector<Base::Ptr> m_data;
};

BOOST_SERIALIZATION_SPLIT_FREE(Base)
BOOST_SERIALIZATION_SPLIT_FREE(Derived)
BOOST_SERIALIZATION_SPLIT_FREE(Container)
BOOST_CLASS_EXPORT_GUID(Derived, "Derived")

namespace boost {
namespace serialization {

/// Serialization of base class ///
template<class Archive>
void save(Archive& ar, const Base& m, unsigned int) {
auto d = m.getDouble();
auto i = m.getInteger();
ar& make_nvp("doublevalue", d);
ar& make_nvp("intvalue", i);
}

template<class Archive>
void load(Archive& ar, Base& m, unsigned int) {
double d;
int i;

ar& make_nvp("doublevalue", d);
ar& make_nvp("intvalue", i);

m.setDouble(d);
m.setInteger(i);
}

/// serialization of derived class ///
template<class Archive>
void save(Archive& ar, const Derived& m, unsigned int) {
ar& make_nvp("base", base_object<const Base>(m));
ar& make_nvp("stringvalue", m.getString());
}

template<class Archive>
void load(Archive& ar, Derived& m, unsigned int) {
std::string s;

ar& make_nvp("base", base_object<Base>(m));
ar& make_nvp("stringvalue", s);

m.setString(s);
}

/// serialization of container class ///
template<class Archive>
void save(Archive& ar, const Container& m, unsigned int) {
ar& make_nvp("data", m.getDataVector());
}

template<class Archive>
void load(Archive& ar, Container& m, unsigned int) {
std::vector<Base::Ptr> data;

ar& make_nvp("data", data);

for (const auto& it : data) {
m.addData(it);
}
}

}
} // namespace boost::serialization


int main(int argc, char *argv[]) {
// Initialize container
Container container;
auto baseObj = std::make_shared<Base>();
baseObj->setDouble(4.3);
baseObj->setInteger(6);
auto derivedObj = std::make_shared<Derived>();
derivedObj->setDouble(1.1);
derivedObj->setInteger(2);
derivedObj->setString("string in derived");
container.addData(baseObj);
container.addData(derivedObj);

// Print serialization of Base
std::stringstream basess;
boost::archive::xml_oarchive baseoa{basess};
baseoa << boost::serialization::make_nvp("baseclass", baseObj);
std::cout << basess.str() << std::endl;

// Print serialization of Derived
std::stringstream derivedss;
boost::archive::xml_oarchive derivedoa{derivedss};
derivedoa << boost::serialization::make_nvp("derivedclass", derivedObj);
std::cout << derivedss.str() << std::endl;

// Print serialization of Container
std::stringstream containerss;
boost::archive::xml_oarchive containeroa{containerss};
containeroa << boost::serialization::make_nvp("containerclass", container);
std::cout << containerss.str() << std::endl;
return 0;
}

当我运行程序时,我打印了 baseObj 的序列化那是 Base 的共享指针:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="17">
<baseclass class_id="0" tracking_level="0" version="1">
<px class_id="1" tracking_level="1" version="0" object_id="_0">
<doublevalue>4.29999999999999982e+00</doublevalue>
<intvalue>6</intvalue>
</px>
</baseclass>

这似乎是正确的,因为我同时拥有 doublevalueintvalue在基类中定义。

然后我打印 derivedObj 的序列化那是 Derived 的共享指针:

<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="17">
<derivedclass class_id="0" tracking_level="0" version="1">
<px class_id="1" tracking_level="1" version="0" object_id="_0">
<base class_id="2" tracking_level="1" version="0" object_id="_1">
<doublevalue>1.10000000000000009e+00</doublevalue>
<intvalue>2</intvalue>
</base>
<stringvalue>string in derived</stringvalue>
</px>
</derivedclass>

它似乎按预期工作,因为我有基类数据,还有 stringvalue派生类的。

现在,如果我将两个指针都放入 std::vector<std::shared_ptr<Base>>Container , 我期待同时序列化 baseObjderivedObj正确。相反,这是输出:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="17">
<containerclass class_id="0" tracking_level="0" version="0">
<data class_id="1" tracking_level="0" version="0">
<count>2</count>
<item_version>1</item_version>
<item class_id="2" tracking_level="0" version="1">
<px class_id="3" tracking_level="1" version="0" object_id="_0">
<doublevalue>4.29999999999999982e+00</doublevalue>
<intvalue>6</intvalue>
</px>
</item>
<item>
<px class_id_reference="3" object_id="_1">
<doublevalue>1.10000000000000009e+00</doublevalue>
<intvalue>2</intvalue>
</px>
</item>
</data>
</containerclass>

vector 的两个元素都序列化为 Base指针。

我尝试使用 BOOST_CLASS_EXPORT_GUID(Derived, "Derived")文档中建议的宏,但它似乎不起作用。

我还尝试了 this post 中提出的解决方案, 通过评论 BOOST_CLASS_EXPORT_GUID(Derived, "Derived")并使用 register_typeContainer的连载中,但问题依然存在:

/// serialization of container class ///
template<class Archive>
void save(Archive& ar, const Container& m, unsigned int) {
ar.template register_type<Derived>();
ar& make_nvp("data", m.getDataVector());
}

template<class Archive>
void load(Archive& ar, Container& m, unsigned int) {
ar.template register_type<Derived>() ;
std::vector<Base::Ptr> data;

ar& make_nvp("data", data);

for (const auto& it : data) {
m.addData(it);
}
}

如何正确序列化 Derived类存储在 Base 的共享指针 vector 中?

最佳答案

在派生类的情况下,部分问题可能是 std::shared_ptr 的行为。因此,您有必要将 std::shared_ptr 替换为普通指针。

struct A
{

};

struct B : public A
{

};

void fun(const std::shared_ptr<A>& base)
{
std::cout << typeid(base).name() << std::endl;
}

int main(int argc, char *argv[]) {
auto a=std::make_shared<A>();
auto b=std::make_shared<B>();

std::cout << typeid(a).name() << std::endl;
std::cout << typeid(b).name() << std::endl;
fun(a);
fun(b);
}

这给了你,你可能认为第二行和第四行是相等的:

class std::shared_ptr<struct A>
class std::shared_ptr<struct B>
class std::shared_ptr<struct A>
class std::shared_ptr<struct A>

第二个但不是很明显的一点是,你的基类应该至少包含一个 virtual function .您可以通过仅包含以下内容使析构函数成为虚函数:

virtual ~Base() {};

文档说:

It turns out that the kind of object serialized depends upon whether the base class (base in this case) is polymophic or not. If base is not polymorphic, that is if it has no virtual functions, then an object of the type base will be serialized. Information in any derived classes will be lost. If this is what is desired (it usually isn't) then no other effort is required.

在我用普通指针替换所有 shared_ptr 并添加虚拟析构函数后,结果如我所愿,我获得了最后一部分的以下输出:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="17">
<containerclass class_id="0" tracking_level="0" version="0">
<data class_id="1" tracking_level="0" version="0">
<count>2</count>
<item_version>0</item_version>
<item class_id="2" tracking_level="1" version="0" object_id="_0">
<doublevalue>4.29999999999999982e+00</doublevalue>
<intvalue>6</intvalue>
</item>
<item class_id="3" class_name="Derived" tracking_level="1" version="0" object_id="_1">
<base object_id="_2">
<doublevalue>1.10000000000000009e+00</doublevalue>
<intvalue>2</intvalue>
</base>
<stringvalue>string in derived</stringvalue>
</item>
</data>
</containerclass>

关于c++ - 使用 boost::serialization 将派生类指针序列化为 vector 的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56984607/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com