Does the boost serialization library support serialization of std::unique_ptr?
I tried to compile the code below, but if I include the
boost::archive::text_oarchive oa(ofs); oa << g; line,
the compiler (btw gcc4.7 with -std=c++11 flag) throws an error
/usr/include/boost/serialization/access.hpp:118:9: error: ‘class std::unique_ptr’ has no member named ‘serialize’
#include <iostream>
#include <memory>
#include <fstream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
class MyDegrees
{
public:
void setDeg(int d){deg = d;}
int getDeg()const {return deg;}
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{ ar & deg; }
int deg;
};
class gps_position
{
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{ ar & degrees; }
std::unique_ptr<MyDegrees> degrees;
public:
gps_position(): degrees(std::unique_ptr<MyDegrees>(new MyDegrees)){};
void setDeg(int d){degrees->setDeg(d);}
int getDeg() const {return degrees->getDeg();}
};
int main()
{
std::ofstream ofs("filename");
gps_position g;
g.setDeg(45);
std::cout<<g.getDeg()<<std::endl;
{// compiler error, fine if commented out
boost::archive::text_oarchive oa(ofs); oa << g;
}
return 0;
}
No, there is no out of the box adaption. You will need to provide a non-intrusive adapter yourself. See the tutorial here to get an idea how to do that.
I'm not sure how to interpret this list, but it seems like support for this was added sometime after 1.48. I am using 1.58 and it is included. Just
#include <boost/serialization/unique_ptr.hpp>
and then it will work as follows:
#include <memory>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/unique_ptr.hpp>
#include <fstream>
class Point
{
public:
Point() { }
float x = 1.;
float y = 2.;
float z = 3.;
private:
friend class boost::serialization::access;
template<class TArchive>
void serialize(TArchive & archive, const unsigned int version)
{
archive & x;
archive & y;
archive & z;
}
};
void ValidUniquePointer()
{
std::unique_ptr<Point> p(new Point());
std::ofstream outputStream("test.txt");
boost::archive::text_oarchive outputArchive(outputStream);
outputArchive << p;
outputStream.close();
// read from a text archive
std::unique_ptr<Point> pointRead;
std::ifstream inputStream("test.txt");
boost::archive::text_iarchive inputArchive(inputStream);
inputArchive >> pointRead;
std::cout << pointRead->x << " " << pointRead->y << " " << pointRead->z << std::endl;
}
void NullUniquePointer()
{
std::unique_ptr<Point> p;
std::ofstream outputStream("test.txt");
boost::archive::text_oarchive outputArchive(outputStream);
outputArchive << p;
outputStream.close();
// read from a text archive
std::unique_ptr<Point> pointRead;
std::ifstream inputStream("test.txt");
boost::archive::text_iarchive inputArchive(inputStream);
inputArchive >> pointRead;
if(pointRead != nullptr) {
std::cout << pointRead->x << " " << pointRead->y << " " << pointRead->z << std::endl;
}
else {
std::cout << "Pointer is null!" << std::endl;
}
}
int main()
{
ValidUniquePointer();
NullUniquePointer();
return 0;
}
as mentioned by pmr, I managed to come up the following solution, and at the first glance, everything works. In hope that someone could find it useful:
#include <iostream>
#include <memory>
#include <fstream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
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
class MyDegrees
{
public:
void setDeg(int d){deg = d;}
int getDeg()const {return deg;}
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{ ar & deg; }
int deg;
};
class gps_position
{
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{ ar & degrees; }
std::unique_ptr<MyDegrees> degrees;
public:
gps_position(): degrees(std::unique_ptr<MyDegrees>(new MyDegrees)){};
void setDeg(int d){degrees->setDeg(d);}
int getDeg() const {return degrees->getDeg();}
};
int main()
{
std::ofstream ofs("filename");
gps_position g;
g.setDeg(45);
std::cout<<g.getDeg()<<std::endl;
{ boost::archive::text_oarchive oa(ofs); oa << g; }
gps_position newg;
{
std::ifstream ifs("filename");
boost::archive::text_iarchive ia(ifs);
ia >> newg;
std::cout<<newg.getDeg()<<std::endl;
}
return 0;
}
recent versions of boost serialization provide support for all std smart pointer types.