For a while now I've had a basic serialization system implemented in my game, and while it works really well for relatively trivial types (arrays, transforms, etc) it's been pretty much useless for doing anything real because it has no way of handling pointers.
If I could make the assertion that all pointed-to objects were allocated identically (via 'new', for example), this wouldn't be an issue because the first time you hit a pointer (owning or not) to anything in the archive, you just new that shit up and deserialize it. Unfortunately, that simply isn't the case.
After a bit of brainstorming, I've come to the conclusion that to properly deserialize pointers you need to be able to do two passes. The first would instantiate all objects and set their trivial values, the second would set the value of non-owning pointers (now that everything has been instantiated), using a mapping of archive IDs to their new addresses that was created in the first pass.
At the moment my serialization system is split into two different functions: 'ToArchive' and 'FromArchive', which are both called recursively. Since 'ToArchive' is pretty much fine as it is, I've come up with two solutions for adding a second pass to the 'FromArchive' function.
A) I would split that function into 'PreFromArchive' and 'PostFromArchive' (the absence of either would indicate that object is simply not touched during that phase, the absence of both would indicate the object cannot be deserialized). They would each be called recursively (starting with the root object), and pointers would be set in the second function. This is nice because it's very simple, but could be inefficient because you're visiting almost everything twice. It's also nice because you can do anything else that might need to happen after you've deserialized everything, including validation for example.
B) Raw pointers (and anything else that needs to be touched up at the end) could add themselves to a queue that gets iterated at the very end. This may be more performant, but could also be error-prone since it creates the possibility of dangling pointers (imagine an object in an array deferring itself, and then the array being reallocated). It could also hypothetically create chicken-and-egg scenarios, where an object deferred itself to wait on the instantiation of another object, even though it in fact was responsible for instantiating that object.
Neither seems terribly difficult to implement at the end of the day, but I'd like some input before I dive into this. Are there any other solutions I'm not considering?
Thanks