Implementing object tracking, like in Boost::Serialization

438 views Asked by At

I'm implementing a "clone" function for a graph of objects in C++ and part of the problem is to ensure that if there are two pointers to the same object, it is not cloned twice. I've done this by keeping a map<void*, void*> that keeps the original object as the key and the cloned version as the value. When cloning an object, I use a template function to check if the object is in the map - if so, I return it with a static_cast<T*>, otherwise, I clone it and store the original and clone in the map with an implicit conversion to void*.

The problem with this scheme is that if an object is referred to in two places by different types (eg. by the interface vs the concrete type) the cast to void* might not result in the same value. This would mean that object is cloned twice.

I looked on the web for existing solutions to this and realized that Boost.Serialization has to deal with the same problem. But after trawling through its source, I couldn't find the part that actually tracks pointers to objects.

Can anyone help by suggesting a design that works, or by pointing out the part of the Boost code that does this?

2

There are 2 answers

6
Xeo On BEST ANSWER

Before storing, cast the pointer with a dynamic_cast<void*> - this will give you a void pointer to the most derived object; this void pointer will, for the same objects, have the same address stored.

See also this question.

0
edA-qa mort-ora-y On

I don't believe boost serialization handles this in some super clever way. Look at the base_object function -- it appears you have to manually say what the base class is. It's obvious from here then how to get the same pointer. Also note that for serializing derived classes only virtual classes will be saved correctly that way, non-virtuals, like standard layout types, you must serialize the derived class. I have no idea if they handle a shared pointer in that case.

So the basic idea would be that if you have a virtual class the base must have a "serial" function of sorts. If you cast to this base you have a common pointer and can still call the virtual serial function.

You might be better off just creating a global identify<T> template and specialize it for all types that need it. Could be error-prone, but by no means does the boost approach avoid errors either.

I've done a lot of work with boost serialization but have avoided the pointer logic -- it just got really confusing, so I basically just don't do that level of serialization (no pointers in my serialized data).