Повысить сериализацию класса, заключающего указатель

У меня есть класс Ptr который оборачивает указатель Этот указатель может обрабатывать такие структуры, как Ptr<A> где A может быть сложной структурой или примитивами, такими как Ptr<double>, Я хотел бы указать save а также load функции Ptr serilaization, чтобы работать для обоих этих случаев.
Здесь я пытаюсь воспроизвести упрощенный пример:

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;
    */
}

Живой пример

Как видите, сериализация для 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) [with 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:: archive:: 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 ответ

Решение

Решение загадки состоит в том, что сериализация примитивных типов через указатель не поддерживается.

Причина в том, что отслеживание объектов отключено для примитивных типов. это задокументировано здесь:

Особые соображения / Отслеживание объектов

По умолчанию типы данных, обозначенные как примитивные по признаку сериализации класса реализации, никогда не отслеживаются. Если необходимо отслеживать общий примитивный объект через указатель (например, long, используемый в качестве счетчика ссылок), он должен быть заключен в класс / структуру, чтобы он был идентифицируемым типом. Альтернатива изменения уровня реализации long может повлиять на все long, сериализованные во всей программе - вероятно, не то, что намеревались бы.

Вот минималистский пример, который показывает коренную причину изолированно:

Жить на Колиру

#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 является примитивным типом.

Другие вопросы по тегам