问题
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
versusv_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