Serializing std::vector of unique_ptr using boost::serialization fails on linux

≯℡__Kan透↙ 提交于 2019-12-23 20:16:35

问题


I am encountering an issue with using boost serialization of a std::vector of std::unique_ptr's. The type of the unique_ptr does not matter, and in the below example, integers are used:

#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());

}

As specified by the comment, the program fails to compile when trying to use the deserialize operator from the input archive into a std::vector<std::unique_ptr<...>>.

The error thrown is:

/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)...); }
^

which is thrown in GCC's new_allocator.h, line 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: ...

The above example build and runs as expected on both Windows and OS X - This only fails to compile on linux.
The app is linked to the following libraries (using CMake):

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

The link command is equal on all platforms. I am using boost 1.67 and compiling on Ubuntu 16.04 using GCC 5.4.0

The following CMakeLists.txt is used for the project:

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:


You don't need to provide serialization for the vector. In fact, doing so broke things because you failed to provide NVP wrapping in your serialize function.

Just remove that.

Next up, Serialization does not expect (unique pointers) to primitive types. For that reason in this example it does matter whether you use int or some trivial struct X.

Side note: you need consistent XML names on (de)serialize. You had v_out versus v_in which doesn't work.

Fixed sample:

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());
}

Alternatively

To have non-intrusive serialization:

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 On Coliru



来源:https://stackoverflow.com/questions/50038329/serializing-stdvector-of-unique-ptr-using-boostserialization-fails-on-linux

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!