Сериализация std :: vector unique_ptr с использованием boost :: serialization не работает в Linux - PullRequest
0 голосов
/ 26 апреля 2018

У меня возникла проблема с использованием расширенной сериализации std :: vector из std :: unique_ptr. Тип unique_ptr не имеет значения, и в приведенном ниже примере используются целые числа:

#include <boost/serialization/unique_ptr.hpp>

#include <boost/serialization/vector.hpp>

#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <fstream>

namespace boost {
namespace serialization {

template <class Archive>
void serialize(Archive& ar, std::vector<unique_ptr<int>>& g, const unsigned int version) {
    ar& g;
}

}  // namespace serialization
}  // namespace boost

int main(int argc, char** argv){
std::vector<std::unique_ptr<int>> v_out;
const std::string archName = "test_arch.xml";

v_out.push_back(make_unique<int>(1));
v_out.push_back(make_unique<int>(2));
v_out.push_back(make_unique<int>(3));

// Serialize vector
std::ofstream ofs(archName);
{
    boost::archive::xml_oarchive oa(ofs);
    oa << BOOST_SERIALIZATION_NVP(v_out);
}
ofs.close();

std::vector<std::unique_ptr<int>> v_in;
// Deserialize vector
std::ifstream ifs(archName);
{
    boost::archive::xml_iarchive ia(ifs);
    // next line fails to build
    ia >> BOOST_SERIALIZATION_NVP(v_in);
}
ifs.close();


remove(archName.c_str());

}

Как указано в комментарии, программе не удается скомпилировать при попытке использовать оператор десериализации из входного архива в std::vector<std::unique_ptr<...>>.

Выдается ошибка:

/usr/include/c++/5/ext/new_allocator.h:120: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]’
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
^

, который добавляется в GCC new_allocator.h , строка 120.

116: #if __cplusplus >= 201103L
117:       template<typename _Up, typename... _Args>
118:         void
119:         construct(_Up* __p, _Args&&... __args)
120:    { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
121: 
122:       template<typename _Up>
123:         void 
124:         destroy(_Up* __p) { __p->~_Up(); }
125: #else
126: ...

Вышеприведенный пример компоновки и работает как ожидалось, как на Windows, так и на OS X - Это не удается скомпилировать только на Linux.
Приложение связано со следующими библиотеками (используя CMake):

target_link_libraries(app ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_SERIALIZATION_LIBRARY})

Команда link одинакова на всех платформах. Я использую Boost 1.67 и компилирую в Ubuntu 16.04, используя GCC 5.4.0

Для проекта используется следующий файл CMakeLists.txt:

set (CMAKE_CXX_STANDARD 14)

add_executable(test main.cpp)

set(Boost_NO_SYSTEM_PATHS OFF)
set(BOOST_INCLUDEDIR "$ENV{BOOST_ROOT}")

find_package(Boost COMPONENTS serialization REQUIRED)

target_link_libraries(test  ${Boost_SERIALIZATION_LIBRARY})

1 Ответ

0 голосов
/ 26 апреля 2018

Вам не нужно предоставлять сериализацию для вектора.Фактически, это сломало вещи, потому что вы не смогли обеспечить обертывание NVP в вашей функции сериализации.

Просто удалите это.

Далее, сериализация не ожидает (уникальные указатели) для примитивных типов.По этой причине в этом примере имеет значение , независимо от того, используете ли вы int или какую-то тривиальную структуру X.

Примечание: вам нужны согласованные имена XML на(де) сериализации.У вас был v_out против v_in, который не работает.

Фиксированный пример:

Live On Coliru

#include <boost/serialization/unique_ptr.hpp>

#include <boost/serialization/vector.hpp>

#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <fstream>
#include <memory>

struct X {
    X(int = 0) {}
    template <typename Ar> void serialize(Ar&, unsigned) {}
};

int main() {
    std::vector<std::unique_ptr<X> > v_out;
    const std::string archName = "test_arch.xml";

    v_out.push_back(std::make_unique<X>(1));
    v_out.push_back(std::make_unique<X>(2));
    v_out.push_back(std::make_unique<X>(3));

    // Serialize vector
    {
        std::ofstream ofs(archName);
        boost::archive::xml_oarchive oa(ofs);
        oa << boost::serialization::make_nvp("root", v_out);
    }

    // Deserialize vector
    {
        std::ifstream ifs(archName);
        boost::archive::xml_iarchive ia(ifs);
        // next line fails to build
        std::vector<std::unique_ptr<X> > v_in;
        ia >> boost::serialization::make_nvp("root", v_in);
    }

    remove(archName.c_str());
}

В качестве альтернативы

Для неинтрузивной сериализации:

struct X {
    X(int i = 0) : _i(i) {}
    int _i;
};

namespace boost { namespace serialization {
    template <class Archive>
    void serialize(Archive& ar, X& x, unsigned) {
        ar& BOOST_SERIALIZATION_NVP(x._i);
    }
} }

Live OnColiru

...