How Can Boost::Serialization Be Used with Std::Shared_Ptr from C++11

How can boost::serialization be used with std::shared_ptr from C++11?

As of Boost 1.56, the serialization library has built-in support for std::shared_ptr. You do not need to implement your own serialization helper functions if you can use a more recent version of the library.

boost serialize and std::shared_ptr

I suspect you are missing an include,

#include <boost/serialization/shared_ptr.hpp>

link, at the bottom

Also, the example makes it look like aliasing and cycles are taken care of by default.

_Of course, having cycles will lead to potential memory leaks with shared_ptr that have nothing to do with serialization, and you'll still have to heed those (by avoiding cycles or judicious use of weak_ptr)_

See also:

  • Template serialization - shared_ptr
  • shared_ptrRevisited

C++ shared_ptr serialization

You probably forgot to include

#include <boost/serialization/shared_ptr.hpp>

c++11 shared_ptr + Boost::Serialization

I am not sure if this is the best way to do this but it seems to work.

Changed the namespace and added this load method to shared_ptr specialization header copied from Boost::shared_ptr specialization:

template<class Archive, class T>
inline void load(
Archive & ar,
std::shared_ptr< T > &t,
const unsigned int /* file_version */
){
T * t_ptr;
ar >> boost::serialization::make_nvp("px", t_ptr);
t = std::shared_ptr<T>(t_ptr);
}

How do I make boost::serialization work with std::shared_ptr?

No, std::shared_ptr and boost::shared_ptr are unrelated class templates.

Boost.Serizalization doesn't support std::shared_ptr out of the box, but you can add such a support in your application - just take a look at <boost/serialization/shared_ptr.hpp> header.

How to know if shared_ptr was already serialized to boost archive

The code smell is using a shared_ptr where unique ownership must be guaranteed. What are you going to do when you find a violation? Assert? std::terminate?

You could make a serialization wrapper that adds the check on de-serialization.

You will depend on library implementation details, because - apparently - while loading there will be a temporary copy of the shared_ptr:

Live On Coliru

#undef NDEBUG
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/wrapper.hpp>
#include <iostream>

template <typename SP> struct Unique {
SP& _ref;
Unique(SP& r):_ref(r){}

template <typename Ar>
void serialize(Ar& ar, unsigned) {
if constexpr (typename Ar::is_saving{}) {
if (_ref && not _ref.unique())
throw std::logic_error("Shared ownership not allowed");
}
ar & _ref;
if constexpr (typename Ar::is_loading{}) {
if (_ref && _ref.use_count() != 2)
throw std::logic_error("Shared ownership not allowed");
}
}
};

template <typename SP>
struct boost::serialization::is_wrapper<Unique<SP>> : boost::mpl::true_ {};

struct Data {
int a,b,c;
void serialize(auto& ar, unsigned) { ar & a & b & c; }
};

static std::string do_write(auto const&... data) {
std::ostringstream oss;
boost::archive::text_oarchive oa(oss);
(oa << ... << data);
return oss.str();
}

static void do_read(std::string const& str, auto&&... data)
{
std::istringstream iss(str);
boost::archive::text_iarchive ia(iss);
(ia >> ... >> data);
}

int main()
{
auto data = std::make_shared<Data>(1, 2, 3);
assert(data.unique());

// okay:
{
auto txt = do_write(data, data, data);
do_read(txt, data);
std::cout << "L:" << __LINE__ << " Success " << std::endl;
}

// still okay:
{
Unique ud{data};
auto txt = do_write(ud);
do_read(txt, ud);
std::cout << "L:" << __LINE__ << " Success " << std::endl;
assert(data.unique());
}

// not okay because not unique:
try
{
auto data_shared(data);
Unique ud{data}, ud_shared{data_shared};
assert(!data.unique());
assert(!data_shared.unique());

auto txt = do_write(ud, ud_shared);
do_read(txt, ud, ud_shared);
std::cout << "L:" << __LINE__ << " Success " << std::endl;
}catch(std::exception const& e) {
std::cout << "L:" << __LINE__ << " Failure " << e.what() << std::endl;
}
}

Prints

L:57 Success 
L:65 Success
L:81 Failure Shared ownership not allowed

Summary

Don't do this, because you can't cleanly do it. The alternative is far worse (delving into the object tracking implementation details as some commenters suggested).

Simply

  • tighten the type constraints to express your invariant
  • perhaps add a validation member to check the invariant

Boost serialization doesn't work with shared_ptr<int>

From the Boost source code around that assertion:

// The most common cause of trapping here would be serializing
// something like shared_ptr<int>. This occurs because int
// is never tracked by default. Wrap int in a trackable type
BOOST_STATIC_ASSERT((tracking_level< T >::value != track_never));

Basically, in order to serialize things like shared_ptr properly, the pointed-to objects need to be centrally tracked during the serialization process (to identify when multiple pointers point to the same object, so they don't lead to two copies of the object being serialized). Tracking an object is more expensive than not tracking it, though, so primitive types are not tracked (the assumption being that there's gonna be a lot of them). Essentially, this makes it impossible to serialize shared_ptr<primitive_type> without mucking with the Boost sources. The solution, as the comment says, is to instead serialize some UDT containing an int.

boost serialization std::unique_ptr support

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.



Related Topics



Leave a reply



Submit