"Pointer Conflict" Errors in the Boost Serialization Library

The Boost Serialization library offers facilities for saving and restoring C++ data structures to/from sequential representations (e.g., for saving and loading to files). It is generally easy to use and handles most structures correctly, including pointers, circular lists, etc.

One error that users encounter occasionally with this library is the "pointer conflict" error (''archive_exception::pointer_conflict'' exception). This error can be demonstrated with the following simple program:

// Bojan Nikolic <bojan@bnikolic.co.uk>

#include <fstream>
#include <boost/archive/text_oarchive.hpp>

struct A {

  int n;

  template<class Archive>
  void serialize(Archive & ar, const unsigned int version)
  {
    ar & n;
  }
};


int main()
{
  std::ofstream ofs("test");

  A a1;
  A *pa=&a1;

  // This works fine
  {
    boost::archive::text_oarchive oa(ofs);
    oa<<a1;
  }
  // This works too
  {
    boost::archive::text_oarchive oa(ofs);
    oa<<pa;
  }
  // This also
  {
     boost::archive::text_oarchive oa(ofs);
     oa<<a1<<pa;
  }
  // This does *not* work
  {
    boost::archive::text_oarchive oa(ofs);
    oa<<pa<<a1;
  }
  return 0;
}

In fact this error will always happen when any object is serialised first trough a pointer and then as a reference. Serialising the object first as a reference and subsequently through pointers does not cause errors.

The reason why this error is raised can be easily understood by considering what happens during de-serialisation, i.e., reconstruction of in-memory data structures from their sequential representations (the word sequential is key here!). The reverse of the first output statement above is:

A a1;
ia>>a1;

This code means construct object "a1" on the stack and load its contents from the archive. It works exactly as expected.

Now consider the reverse of the last output in the example above:

A a1, *pa;
ia>>pa>>a1;

This code is to construct object "a1" on the stack and also allocate a pointer "pa" on the stack too. The sequence "ia>>pa" means load the saved object and store in the pointer pa -- this is obviously implemented by allocating memory on the heap, loading contents from serialisation archive, and storing the address of the memory in "pa".

Now, the next instruction is ">>a1" which means load the stored object directly into a1. However, both of these objects are in fact one of the same object, and we have already constructed this object on the heap! Therefore if we wanted to in fact store this object in memory allocated for "a1" we would have to go back and re-write the pointer stored in pa.

Therefore, in order to be able to sequential de-serialisation of pointers and references to identical objects, the references must come first, so that object are loaded in correct, pre-determined, locations in memory!

In practice, if you need to serialise pointers at all, these problem are best solved by consistently using pointers consistently for all object access and not using direct references at all.