首页 文章

提升包装指针的类的序列化

提问于
浏览
1

我有一个包含指针的类 Ptr . 该指针可以处理诸如 Ptr<A> 之类的结构,其中 A 可以是复杂的结构或基元,例如 Ptr<double> . 我想指定 Ptr serilaization的 saveload 函数来适用于这两种情况 .
在这里,我尝试重现一个简化的例子:

struct A { 
    A(int aa) : a(aa) {} 
    int a; 
    template<class Archive>
    void serialize(Archive &ar, const unsigned int version) {
        ar & BOOST_SERIALIZATION_NVP(a);
    }
};

template <typename T>
struct Ptr {
    Ptr() : m_elem(0) {}
    Ptr(const T* elem) { m_elem = (elem ? new T(*elem) : 0); };
    const T& operator*() const { return *m_elem; };
    T& operator*()  { return *m_elem; };
    const T* operator->() const { return m_elem;};
    T* operator->() { return m_elem;};

    // [...] other ctor, copy, del, etc...

    T* m_elem;
};

namespace boost { namespace serialization {

template<class Archive, class T>
void save(Archive & ar, const Ptr<T> &ptr, const unsigned int version) {
    T* base_pointer = (ptr.m_elem);
    ar & boost::serialization::make_nvp("Ptr", base_pointer);
}

template<class Archive, class T>
void load(Archive & ar, Ptr<T> &ptr, const unsigned int version) {
    T *base_pointer;
    ar & boost::serialization::make_nvp("Ptr", base_pointer);
    ptr.m_elem = base_pointer;
}

template<class Archive, class T>
void serialize(Archive & ar, Ptr<T> &ptr, const unsigned int version)
{
    boost::serialization::split_free(ar, ptr, version);
}

}} // end namespace

int main() {
    Ptr<A> p1(new A(4));
    std::cout << p1.m_elem->a << std::endl;
    Ptr<double> p2(new double(2.0));
    std::cout << *(p2.m_elem) << std::endl;

    // The serialization for Ptr<A> seems to work
    std::ostringstream archive_ostream;
    boost::archive::xml_oarchive oa(archive_ostream);
    oa << BOOST_SERIALIZATION_NVP(p1); 
    std::cout << archive_ostream.str() << std::endl;

    // Serialization for Ptr<double> does not compile
    /*
    std::ostringstream archive_ostream2;
    boost::archive::xml_oarchive oa2(archive_ostream2);
    oa2 << BOOST_SERIALIZATION_NVP(p2); 
    std::cout << archive_ostream2.str() << std::endl;
    */
}

Live example

正如您所看到的, Ptr<A> 的序列化似乎有效(我仍然不确定它是否足够安全) . 但是, Ptr<double> 的序列化未编译 .

错误输出是:

main.cpp:实例化'void boost :: serialization :: save(Archive&,const Ptr&,unsigned int)[with Archive = boost :: archive :: xml_oarchive; T = A]':/ usr / local /include/boost/serialization/split_free.hpp:45:13:需要'static void boost :: serialization :: free_saver :: invoke(Archive&,const T&,unsigned int)[与Archive = boost :: archive :: xml_oarchive; T = Ptr]'/usr/local/include/boost/serialization/split_free.hpp:74:18:需要'void boost :: serialization :: split_free(Archive&,T&,unsigned int)[with Archive = boost ::存档:: xml_oarchive; T = Ptr]'main.cpp:57:34:需要'void boost :: serialization :: serialize(Archive&,Ptr&,unsigned int)[with Archive = boost :: archive :: xml_oarchive; T = A]'

因此,我正在寻找一个正确的 Ptr 序列化!

1 回答

  • 1

    谜语的解决方案就是不支持通过指针序列化基本类型 .

    原因是对基本类型禁用了对象跟踪 . 这在此处记录:

    特殊注意事项/对象跟踪默认情况下,从不跟踪由实现级别类序列化特征指定的基元数据类型 . 如果希望通过指针(例如,长期用作引用计数)来跟踪共享原始对象,则应将其包装在类/结构中,以使其成为可识别的类型 . 改变long的实现级别的替代方案将影响整个程序中序列化的所有longs - 可能不是人们想要的 .

    这是一个极简主义的示例,它显示了孤立的根本原因:

    Live On Coliru

    #include <boost/archive/xml_iarchive.hpp>
    #include <boost/archive/xml_oarchive.hpp>
    #include <iostream>
    #include <sstream>
    
    int main() {
        // Serialization for double* does not compile
        double* p(new double(2.0));
        std::cout << *p << std::endl;
    
        std::ostringstream oss;
        boost::archive::xml_oarchive oa(oss);
        oa << BOOST_SERIALIZATION_NVP(p); 
        std::cout << oss.str() << std::endl;
    }
    

    您需要重新考虑序列化计划 . 您希望/需要跟踪什么对象标识?

    您可以跟踪 Ptr<> 对象的身份,并且由于您在实施自定义指针包装器类型时遇到了麻烦,我得到的印象是这可能是您想要/需要的 .

    演示: Live On Coliru

    万一你真的想在这里进行双层对象跟踪(例如,如果你有两个 Ptr<T> 实例指向相同的 T ?),你需要部分专门针对T是基本类型的情况 .

相关问题