Как повысить :: сериализацию можно использовать с std :: unique_ptr из C ++ - PullRequest
0 голосов
/ 21 февраля 2020

Я пытаюсь использовать библиотеку boost :: serialization для сериализации класса (класс A в следующем коде), который включает член std :: unique_ptr.

Среда:

ОС : Windows 10 1909

IDE: Microsoft Visual Studio Community 2019 Версия 16.4.4

Библиотека: boost-serialization 1.72.0 (устанавливается с помощью инструмента vcpkg )

#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/split_free.hpp>
#include <boost/serialization/unique_ptr.hpp>
#include <boost/serialization/vector.hpp>
#include <fstream>
#include <iostream>
#include <memory>

using namespace std;
using namespace boost;

class A
{
public:
    A()
    {
    }

    A(int input_size, int input_value)                  //  Constructor
    {
        this->data = std::make_unique<int[]>(input_size);
        this->size = input_size;
        for (int loop_number = 0; loop_number < size; loop_number++) {
            data[loop_number] = input_value;
        }
    }

    std::unique_ptr<int[]> get_data()
    {
        //  deep copy
        auto return_data = std::make_unique<int[]>(size);
        for (int loop_number = 0; loop_number < size; loop_number++) {
            return_data[loop_number] = data[loop_number];
        }
        return return_data;
    }
    int get_size()
    {
        return this->size;
    }
    ~A()
    {
    }
private:
    std::unique_ptr<int[]> data;
    int size;
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive& ar, const unsigned int version)
    {
        ar& data;
        ar& size;
    }
};


int main()
{
    // create and open a character archive for output
    std::ofstream ofs("filename");

    // create class instance
    const A a_object(10, 5);

    // save data to archive
    {
        boost::archive::text_oarchive oa(ofs);
        // write class instance to archive
        oa << a_object;
        // archive and stream closed when destructors are called
    }

    // ... some time later restore the class instance to its orginal state
    A load_from_file;
    {
        // create and open an archive for input
        std::ifstream ifs("filename");
        boost::archive::text_iarchive ia(ifs);
        // read class state from archive
        ia >> load_from_file;
        // archive and stream closed when destructors are called
    }
    return 0;
}

Компилятор выдает ошибку C2440 и сообщение об ошибке 'initializing': cannot convert from 'int *' to 'const T (*const )'. Он ссылается на% includePath% \ boost \ serialization \ unique_ptr.hpp

template<class Archive, class T>
inline void save(
    Archive & ar,
    const std::unique_ptr< T > &t,
    const unsigned int /*file_version*/
){
    // only the raw pointer has to be saved
    // the ref count is rebuilt automatically on load
    const T * const tx = t.get();
    ar << BOOST_SERIALIZATION_NVP(tx);
}

Кажется, что std :: unique_ptr все еще неудачно сериализуется в библиотеке boost-serialization (версия 1.72.0)? Кроме того, есть ли решение для сериализации класса с членами std :: unique_ptr?

Ответы [ 2 ]

0 голосов
/ 24 февраля 2020

На основании того факта, что std :: unique_ptr не сохраняет размер , ar& data; в шаблонной функции "сериализации", которая используется для сохранения / загрузки данных членов не может быть сериализованным из-за количества данных, неизвестных в этой строке.

template<class Archive>
void serialize(Archive& ar, const unsigned int version)
{
    ar& data;        //    <==    the count of data is unknown 
    ar& size;
}

Итеративный процесс (как показано в следующем коде) интеллектуального указателя «данные» необходим для доступа ко всем действительным data.

for (int i = 0; i < size; ++i)
        ar& data[i];

Таким образом, часть сохранения выглядит следующим образом.

template<class Archive>
void save(Archive& ar, const unsigned int version) const
{
    ar& size;
    for (int i = 0; i < size; ++i)
        ar& data[i];
}

Когда дело доходит до загрузки части, важно выделить пространство интеллектуального указателя перед загрузкой данных, чтобы избежать Ошибка нарушения доступа

template<class Archive>
void load(Archive& ar, const unsigned int version)
{
    ar& size;
    data = std::make_unique<int[]>(size);    //    <==    allocate space of smart pointer first
    for (int i = 0; i < size; ++i)
        ar& data[i];
}

Примечание: Необходимо поставить макрос BOOST_SERIALIZATION_SPLIT_MEMBER (), поскольку функция сохранения / загрузки разделена.

Наконец, часть сериализации в классе А можно сделать следующим кодом:

friend class boost::serialization::access;
template<class Archive>
void save(Archive& ar, const unsigned int version) const
{
    ar& size;
    for (int i = 0; i < size; ++i)
        ar& data[i];
}
template<class Archive>
void load(Archive& ar, const unsigned int version)
{
    ar& size;
    data = std::make_unique<int[]>(size);
    for (int i = 0; i < size; ++i)
        ar& data[i];
}
BOOST_SERIALIZATION_SPLIT_MEMBER()

Ссылка: Учебник по сериализации Boost

0 голосов
/ 21 февраля 2020

В зависимости от версии Boost, которую вы используете, вам может потребоваться реализовать собственный неинтрузивный адаптер, например, так:

namespace boost { 
namespace serialization {

template<class Archive, class T>
inline void save( Archive & ar, const std::unique_ptr< T > &t, const unsigned int /*file_version*/){
    // only the raw pointer has to be saved
    const T * const base_pointer = t.get();
    ar & BOOST_SERIALIZATION_NVP(base_pointer);
}

template<class Archive, class T>
inline void load(Archive & ar,std::unique_ptr< T > &t, const unsigned int /*file_version*/){
    T *base_pointer;
    ar & BOOST_SERIALIZATION_NVP(base_pointer);
    t.reset(base_pointer);
}

template<class Archive, class T>
inline void serialize(Archive & ar,std::unique_ptr< T > &t, const unsigned int file_version){
    boost::serialization::split_free(ar, t, file_version);
}

} // namespace serialization
} // namespace boost

См. this для полного примера .

...