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

Hi everyone, this is my first post so I apologies if I got some of the housekeeping wrong. I did my best. I also realise that this is likely to be a common question but all the responses I could find on Stackoverflow (among others) were related to older implementations of boost. My understanding is that Boost 1.54 is supposed to support `std::shared_ptr`. To illustrate the issue I am having, suppose we want to serialize a class containing a vector of shared pointers, along with a static `load` function that will build the class from a file and a `save` function that will store the instance to a file, and suppose that we can't just use the `serialize` member function for whatever reason (this particular example doesn't really illustrate such a case but in my code I can't use the `serialize` member function so this example doesn't use it either): #include <boost/archive/text_iarchive.hpp> #include <boost/archive/text_oarchive.hpp> #include <boost/serialization/vector.hpp> #include <boost/serialization/shared_ptr.hpp> #include <fstream> #include <memory> #include <vector> class A { public: std::vector<std::shared_ptr<int>> v; void A::Save(char * const filename); static A * const Load(char * const filename); ////////////////////////////////// // Boost Serialization: // private: friend class boost::serialization::access; template<class Archive> void serialize(Archive & ar, const unsigned int file_version) {} }; // save the world to a file: void A::Save(char * const filename) { // create and open a character archive for output std::ofstream ofs(filename); // save data to archive { boost::archive::text_oarchive oa(ofs); // write the pointer to file oa << this; } } // load world from file A * const A::Load(char * const filename) { A * a; // create and open an archive for input std::ifstream ifs(filename); boost::archive::text_iarchive ia(ifs); // read class pointer from archive ia >> a; return a; } namespace boost { namespace serialization { template<class Archive> inline void save_construct_data( Archive & ar, A const * t, unsigned const int file_version ) { ar << t->v; } template<class Archive> inline void load_construct_data( Archive & ar, A * t, const unsigned int file_version ) { ar >> t->v; } } } int main() { } Why doesn't this code compile? What am I doing wrong here? The error message states that 'serialize' is not a member of 'shared_ptr'. Why am I am getting this message?

Arman Schwarz wrote:
Hi everyone, this is my first post so I apologies if I got some of the housekeeping wrong. I did my best.
I also realise that this is likely to be a common question but all the responses I could find on Stackoverflow (among others) were related to older implementations of boost. My understanding is that Boost 1.54 is supposed to support `std::shared_ptr`.
To illustrate the issue I am having, suppose we want to serialize a class containing a vector of shared pointers, along with a static `load` function that will build the class from a file and a `save` function that will store the instance to a file, and suppose that we can't just use the `serialize` member function for whatever reason (this particular example doesn't really illustrate such a case but in my code I can't use the `serialize` member function so this example doesn't use it either):
shared_pointers (boost and std) are not serializable as things stand. For boost:shared_ptr I made special provision inside the archive section of the serialization library. This breaks the fundamental idea of the library which is the decoupling of archives from serialization of data types. In other words, the library guarentees that if one implements serialization for any data type, it will be serializable by any archive class. This doesn't hold true for the shared pointer data types. Due to the high place that shared_ptr holds in the Boost hierarchy I felt I had to break a rule (decoupling archive and serialization) in order to accomodate boost shared_ptr. This was OK .... until now when we have a new shared_ptr to deal with. The real solution is to enhance the serialization API so that the code used for implementing boost::shared_ptr can be applied to other data types which are otherwise unserializable. Unfortunately, this is a non-trivial task which I have yet to get to. So for now I can't offer a real solution other than suggesting one use boost shared pointer rather than std::shared_ptr. I dont' know if this helps - but there it is. Robert Ramey

El 29/09/2013, a las 21:44, "Robert Ramey" <ramey@rrsd.com<mailto:ramey@rrsd.com>> escribió: shared_pointers (boost and std) are not serializable as things stand. [...] This was OK .... until now when we have a new shared_ptr to deal with. The real solution is to enhance the serialization API so that the code used for implementing boost::shared_ptr can be applied to other data types which are otherwise unserializable. Unfortunately, this is a non-trivial task which I have yet to get to. Maybe it's time to recover archive helpers as we discussed some years ago: http://lists.boost.org/Archives/boost/2007/09/127065.php I won't repeat my arguments, but I think helpers were a nice general solution to implement non-trivial serialization for types with shared semantics and other, hard to crack cases. Joaquín M López Muñoz Telefónica Digital ________________________________ Este mensaje se dirige exclusivamente a su destinatario. Puede consultar nuestra política de envío y recepción de correo electrónico en el enlace situado más abajo. This message is intended exclusively for its addressee. We only send and receive email on the basis of the terms set out at: http://www.tid.es/ES/PAGINAS/disclaimer.aspx

JOAQUIN M. LOPEZ MUÑOZ wrote:
El 29/09/2013, a las 21:44, "Robert Ramey" <ramey@rrsd.com> escribió:
shared_pointers (boost and std) are not serializable as things stand.
[...]
This was OK .... until now when we have a new shared_ptr to deal with. The real solution is to enhance the serialization API so that the code used for implementing boost::shared_ptr can be applied to other data types which are otherwise unserializable. Unfortunately, this is a non-trivial task which I have yet to get to.
Maybe it's time to recover archive helpers as we discussed some years ago:
http://lists.boost.org/Archives/boost/2007/09/127065.php
I won't repeat my arguments, but I think helpers were a nice general solution to implement non-trivial serialization for types with shared semantics and other, hard to crack cases.
I agree that this is the required solution. I was unhappy with your solution as it intertwined the solution into the the basic serialization code which is aready almost too complex to understand. What I would like to see is (and plan to do if I get around to it) is to generalize the current approach used to implement the serialization for boost::shared_ptr. The current code implements the "helper" idea in a way that is orthogonal to the rest of the code and doesn't require adding any new template parameters. As I said, I would like to see this generalized. This would entail adding a new facet to the API under the heading "Handling otherwise unserializable type" This would add the facilty of attaching/detaching a "helper" with the appropriate interface. Not all that hard to do and wouldn't complicate other code - but work non the less. Robert Ramey
Joaquín M López Muñoz Telefónica Digital

On 09/29/2013 11:51 PM, Robert Ramey wrote:
boost::shared_ptr. The current code implements the "helper" idea in a way that is orthogonal to the rest of the code and doesn't require adding any new template parameters. As I said, I would like to see this generalized. This would entail adding a new facet
What is the underlying problem? Is that C++ does not have partial specialization for template functions? (i.e. serialize/load/save) If so, then we could solve the problem with functors. I have used this technique to solve a somewhat related problem, namely that my archives required a different serialization for collections than provided by <boost/serialization/serialization.hpp> and friends. The functor part can be seen at: http://sourceforge.net/p/protoc/code/ci/master/tree/include/protoc/serializa...

On Mon, Sep 30, 2013 at 6:48 AM, Robert Ramey <ramey@rrsd.com> wrote:
[...]
This was OK .... until now when we have a new shared_ptr to deal with.
The real solution is to enhance the serialization API so that the code used for implementing boost::shared_ptr can be applied to other data types which are otherwise unserializable. Unfortunately, this is a non-trivial task which I have yet to get to. So for now I can't offer a real solution other than suggesting one use boost shared pointer rather than std::shared_ptr. I dont' know if this helps - but there it is.
No, this helps a lot. I've switched to boost::shared_ptr and everything seems to work. Reading the documentation, I didn't immediately notice that boost/serialization/shared_ptr.hpp was a specialization for the boost shared pointers, not those of the standard library. This lead to my confusion. Cheers, Arman

On Sun, Sep 29, 2013 at 3:58 PM, Arman Schwarz <armanschwarz@gmail.com> wrote:
On Mon, Sep 30, 2013 at 6:48 AM, Robert Ramey <ramey@rrsd.com> wrote:
[...] This was OK .... until now when we have a new shared_ptr to deal with. The real solution is to enhance the serialization API so that the code used for implementing boost::shared_ptr can be applied to other data types which are otherwise unserializable. Unfortunately, this is a non-trivial task which I have yet to get to. So for now I can't offer a real solution other than suggesting one use boost shared pointer rather than std::shared_ptr. I dont' know if this helps - but there it is.
No, this helps a lot. I've switched to boost::shared_ptr and everything seems to work.
Reading the documentation, I didn't immediately notice that boost/serialization/shared_ptr.hpp was a specialization for the boost shared pointers, not those of the standard library. This lead to my confusion.
I remember Peter Dimov making the point that std::shared_ptr needs serialization too, and that it is incorrect for Boost Serialization to get special access to boost::shared_ptr. But here we are. Also keep in mind that in the general case shared_ptr is not serializable. For example, you can't serialize shared_ptr<int> which was created by aliasing from a shared_ptr<foo>. In most usual cases of course it can be serialized non-intrusively. -- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
participants (5)
-
Arman Schwarz
-
Bjorn Reese
-
Emil Dotchevski
-
JOAQUIN M. LOPEZ MUÑOZ
-
Robert Ramey