Jeffrey A. Edlund wrote:
I'm trying to serialize a hierarchical data structure like the following:
class StorageVar;
typedef std::vector<StorageVar> sv_list; typedef std::map<std::string, StorageVar > sv_dict; typedef std::pair<std::string, StorageVar > sv_dict_pair;
typedef boost::variant < boost::shared_ptr<size_t>,boost::shared_ptr<int>,boost::shared_ptr<double>,boost::shared_ptr<std::string>, boost::shared_ptr<std::vector<size_t> >, boost::shared_ptr<std::vector<int> >, boost::shared_ptr<std::vector<double> >, boost::recursive_wrapper<boost::shared_ptr< sv_list > >, boost::recursive_wrapper<boost::shared_ptr< sv_dict > >, boost::recursive_wrapper<boost::shared_ptr< sv_dict_pair > > > StorageVar_data_imp;
class StorageVar_imp { public: StorageVar_imp(): data(new StorageVar_data_imp) {}; boost::shared_ptr<StorageVar_data_imp> data; boost::shared_ptr<sv_dict> attributes; };
class StorageVar { public: boost::shared_ptr<StorageVar_imp> content; StorageVar(): content(new StorageVar_imp) {}; /* Further functionality removed for clarity. */ }
I had been hoping to serialize this nonintrustively, but quickly ran into problems. Here's my understanding of the situation: As has been mentioned on the list before, Boost.Serialize refuses to serialize shared_ptrs to primitive types because tracking is turned off for primitive types and cannot be turned on. Primitive types used in my example include size_t,int,double, and std::string. I can understand (sort of) why you wouldn't want to track all the numeric types, but I don't understand why std::string is considered now considered a primitive. (Looking at boost/serialization/string.hpp indicates that it wasn't a primitive type at some point.)
I didn't want to make std::string a primitive type. It just turned out I had to do it get out of a corner related to the fact that std::string type is used in the serialization header. I also felt that accidently tracking every std::string probably would't be a good idea in any case - so here we are.
The way that's mentioned in the archive to get around this is to use BOOST_STRONG_TYPEDEF(int,tracked_int) etc. This would require that I change the data structure (an intrusive change) and add a static_cast< T&>(variable) everywhere these wrapped variables are used. (This is because the "strong" typedef really just makes a new class with your type inside it with basic methods defined.)
I think you could make a temporary wrapper something like ar & static_cast<BOOST_STRONG_TYPEDEF(int, tracked_int) &> i I don't think the follow should be necessary, but maybe it is. class template<class Archive> serialize( Archive &ar, BOOST_STRONG_TYPEDEF(int, tracked_int) & i, const unsigned version ){ ar & i; }
I might be missing something, but couldn't boost/serialization/shared_ptr.hpp be rewritten to keep track of all the pointers that it sees without turning tracking on for all primitive types?
LOL - be my guest. boost::shared_ptr does not meet the requirements of the "serializable concept". Hence it has to be turned into something that does and that is what is serialized. Sure its inefficient - but its the only think that can be done under the circumstances.
Basically just automatically track anything that's inside a shared_ptr. The programmer shouldn't be storing both a shared_ptr to memory and a normal pointer to the same memory anyway.
Robert Ramey