<p>Firstly, I conclude you <a href="http://rextester.com/JDME53734" rel="nofollow noreferrer">must be using MSVC</a> since your code is not valid standard C++.</p>

<p>Fixing things shows it appears to work properly on <a href="http://coliru.stacked-crooked.com/a/15a3428f1a5f7eff" rel="nofollow noreferrer">Clang</a> and <a href="http://coliru.stacked-crooked.com/a/092f68e30b8cfaf8" rel="nofollow noreferrer">GCC</a>.</p>

<blockquote>
  <p>Enabling AddressSanitizer quickly reveals errors that I /believe/ might originate in the singleton code deep inside Boost Serialization. I'll ignore it for now.</p>
</blockquote>

<p>Due to those errors, I looked at this a long time, trying to see whether the code was to blame.</p>

<p>While doing so, I found that many things could be made a lot simpler.</p>

<ul>
<li><p>you can do without construct-data if you just add <em>private</em> default constructors for serialization purposes.</p>

<p>The important thing about your classes are the invariants, and it's easy to prove that invariants are kept across deserialization this way.</p></li>
<li><p>you can do without the subclasses for each binary operator, because they add literally no behaviour. Consider providing the <code>message</code> constant out-of-band</p></li>
<li><p>instead of making a <code>vector&lt;unique_ptr&gt;</code> you can use a pointer container that implicitly owns its elements. This makes e.g. looking up equivalent pointers a <em>lot</em> easier:</p>

<pre><code>namespace memory_management {
    struct address_less {
        bool operator()(Expr const&amp; a, Expr const&amp; b) const { return &amp;a &lt; &amp;b; }
    };

    static boost::ptr_set&lt;Expr, address_less&gt; pool;
}

void Expr::self_register() { memory_management::pool.insert(this); }
</code></pre></li>
</ul>

<p>All in all things are much shorter:</p>

<pre><code>// AST
struct Expr {
    virtual ~Expr() = default;
    virtual std::vector&lt;Expr const *&gt; children() const { return {}; }
    virtual std::string identity() const = 0;
    void print(int p) const {
        std::cout &lt;&lt; std::setw(p) &lt;&lt; ' ';
        std::cout &lt;&lt; identity() &lt;&lt; "\n";

        for (auto a_kid : children()) {
            a_kid-&gt;print(p + 2);
        }
    }

  protected:
    Expr() { self_register(); }
  private:
    void self_register();

    friend class boost::serialization::access;
    template &lt;class Archive&gt; void serialize(Archive &amp;, unsigned) {}
};

namespace memory_management {
    struct address_less {
        bool operator()(Expr const&amp; a, Expr const&amp; b) const { return &amp;a &lt; &amp;b; }
    };

    static boost::ptr_set&lt;Expr, address_less&gt; pool;
}

void ::Expr::self_register() { memory_management::pool.insert(this); }

struct Int : Expr {
    std::string identity() const override { return "Int[" + std::to_string(n) + "]@"; }
    Int(int nn) : n(nn) {}

  private:
    int const n = 0;

    friend class boost::serialization::access;
    Int() = default;
    template &lt;class Archive&gt; void serialize(Archive &amp;ar, unsigned) {
        ar &amp; boost::serialization::base_object&lt;Expr&gt;(*this) 
           &amp; const_cast&lt;int&amp;&gt;(n);
    }
};

namespace Tags {
    struct Mul;
    struct Div;
    struct Plus;
    struct Minus;
    template &lt;typename T&gt; constexpr char const* const message        = "Unknown";
    template &lt;&gt;           constexpr char const* const message&lt;Mul&gt;   = "Mul";
    template &lt;&gt;           constexpr char const* const message&lt;Div&gt;   = "Div";
    template &lt;&gt;           constexpr char const* const message&lt;Plus&gt;  = "Plus";
    template &lt;&gt;           constexpr char const* const message&lt;Minus&gt; = "Minus";
}

template &lt;class T&gt; struct Op2 : Expr {
    std::vector&lt;Expr const *&gt; children() const override { return { l, r }; }
    std::string identity() const override { return Tags::message&lt;T&gt;; }
    Op2(Expr *ll, Expr *rr) : l(ll), r(rr) {}

  protected:
    friend class boost::serialization::access;
    Op2() = default;
    Expr *l = nullptr;
    Expr *r = nullptr;
    template &lt;class Archive&gt; void serialize(Archive &amp;ar, unsigned) {
        ar &amp; boost::serialization::base_object&lt;Expr&gt;(*this)
           &amp; l &amp; r;
    }
};

using Mul   = Op2&lt;Tags::Mul&gt;;
using Div   = Op2&lt;Tags::Div&gt;;
using Plus  = Op2&lt;Tags::Plus&gt;;
using Minus = Op2&lt;Tags::Minus&gt;;
</code></pre>

<h2>Bonus: A DSL For AST Building</h2>

<p>I thought it would be nicer to be able to say:</p>

<pre><code>Expr const* root((as_expr(3) * 2) + 5 + (as_expr(7) / 25));
</code></pre>

<p>So, let's do that:</p>

<pre><code>namespace builder {
    struct Atom {
        Atom(Expr* expr) : expr(expr)  {}
        Atom(int i) : expr(new Int(i)) {}
        Expr* expr;

        explicit operator Expr const*() const { return expr; }
    };

    template &lt;typename T&gt;
    Atom as_expr(T&amp;&amp; v) { return std::forward&lt;T&gt;(v); }

    Atom operator+(Atom a, Atom b) { return new Plus(a.expr, b.expr); }
    Atom operator-(Atom a, Atom b) { return new Minus(a.expr, b.expr); }
    Atom operator*(Atom a, Atom b) { return new Mul(a.expr, b.expr); }
    Atom operator/(Atom a, Atom b) { return new Div(a.expr, b.expr); }
}
</code></pre>

<h2>LIVE DEMO</h2>

<p><strong><kbd><a href="http://coliru.stacked-crooked.com/a/18cc9cff08b370cb" rel="nofollow noreferrer">Live On Coliru</a></kbd></strong></p>

<pre><code>#include &lt;boost/archive/text_iarchive.hpp&gt;
#include &lt;boost/archive/text_oarchive.hpp&gt;
#include &lt;boost/serialization/base_object.hpp&gt;
#include &lt;boost/serialization/export.hpp&gt;
#include &lt;boost/serialization/serialization.hpp&gt;
#include &lt;boost/ptr_container/ptr_set.hpp&gt;

#include &lt;fstream&gt;
#include &lt;iomanip&gt;
#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;vector&gt;

// AST
struct Expr {
    virtual ~Expr() = default;
    virtual std::vector&lt;Expr const *&gt; children() const { return {}; }
    virtual std::string identity() const = 0;
    void print(int p) const {
        std::cout &lt;&lt; std::setw(p) &lt;&lt; ' ';
        std::cout &lt;&lt; identity() &lt;&lt; "\n";

        for (auto a_kid : children()) {
            a_kid-&gt;print(p + 2);
        }
    }

  protected:
    Expr() { self_register(); }
  private:
    void self_register();

    friend class boost::serialization::access;
    template &lt;class Archive&gt; void serialize(Archive &amp;, unsigned) {}
};

namespace memory_management {
    struct address_less {
        bool operator()(Expr const&amp; a, Expr const&amp; b) const { return &amp;a &lt; &amp;b; }
    };

    static boost::ptr_set&lt;Expr, address_less&gt; pool;
}

void ::Expr::self_register() { memory_management::pool.insert(this); }

struct Int : Expr {
    std::string identity() const override { return "Int[" + std::to_string(n) + "]@"; }
    Int(int nn) : n(nn) {}

  private:
    int const n = 0;

    friend class boost::serialization::access;
    Int() = default;
    template &lt;class Archive&gt; void serialize(Archive &amp;ar, unsigned) {
        ar &amp; boost::serialization::base_object&lt;Expr&gt;(*this) 
           &amp; const_cast&lt;int&amp;&gt;(n);
    }
};

namespace Tags {
    struct Mul;
    struct Div;
    struct Plus;
    struct Minus;
    template &lt;typename T&gt; constexpr char const* const message        = "Unknown";
    template &lt;&gt;           constexpr char const* const message&lt;Mul&gt;   = "Mul";
    template &lt;&gt;           constexpr char const* const message&lt;Div&gt;   = "Div";
    template &lt;&gt;           constexpr char const* const message&lt;Plus&gt;  = "Plus";
    template &lt;&gt;           constexpr char const* const message&lt;Minus&gt; = "Minus";
}

template &lt;class T&gt; struct Op2 : Expr {
    std::vector&lt;Expr const *&gt; children() const override { return { l, r }; }
    std::string identity() const override { return Tags::message&lt;T&gt;; }
    Op2(Expr *ll, Expr *rr) : l(ll), r(rr) {}

  protected:
    friend class boost::serialization::access;
    Op2() = default;
    Expr *l = nullptr;
    Expr *r = nullptr;
    template &lt;class Archive&gt; void serialize(Archive &amp;ar, unsigned) {
        ar &amp; boost::serialization::base_object&lt;Expr&gt;(*this)
           &amp; l &amp; r;
    }
};

using Mul   = Op2&lt;Tags::Mul&gt;;
using Div   = Op2&lt;Tags::Div&gt;;
using Plus  = Op2&lt;Tags::Plus&gt;;
using Minus = Op2&lt;Tags::Minus&gt;;

namespace builder {
    struct Atom {
        Atom(Expr* expr) :expr(expr){}
        Atom(int i) :expr(new Int(i)){}
        Expr* expr;

        explicit operator Expr const*() const { return expr; }
    };

    template &lt;typename T&gt;
    Atom as_expr(T&amp;&amp; v) { return std::forward&lt;T&gt;(v); }

    Atom operator+(Atom a, Atom b) { return new Plus(a.expr, b.expr); }
    Atom operator-(Atom a, Atom b) { return new Minus(a.expr, b.expr); }
    Atom operator*(Atom a, Atom b) { return new Mul(a.expr, b.expr); }
    Atom operator/(Atom a, Atom b) { return new Div(a.expr, b.expr); }
}

BOOST_CLASS_EXPORT(Expr)
BOOST_CLASS_EXPORT(Int)
BOOST_CLASS_EXPORT(Mul)
BOOST_CLASS_EXPORT(Div)
BOOST_CLASS_EXPORT(Plus)
BOOST_CLASS_EXPORT(Minus)

int main() {
    std::cout &lt;&lt; std::unitbuf;
    {
        using builder::as_expr;

        Expr const* root((as_expr(3) * 2) + 5 + (as_expr(7) / 25));

        root-&gt;print(2);
        std::ofstream of("arxiv");

        boost::archive::text_oarchive oa(of);
        oa &lt;&lt; root;
    }
    std::cout &lt;&lt; "===================\n";
    {
        std::ifstream isf("arxiv");
        boost::archive::text_iarchive is(isf);
        Expr *expr = nullptr;
        is &gt;&gt; expr;
        expr-&gt;print(2);
    }

    memory_management::pool.clear(); // no memory leaks
}
</code></pre>

<p>Prints</p>

<pre><code>  Plus
    Plus
      Mul
        Int[3]@
        Int[2]@
      Int[5]@
    Div
      Int[7]@
      Int[25]@
===================
  Plus
    Plus
      Mul
        Int[3]@
        Int[2]@
      Int[5]@
    Div
      Int[7]@
      Int[25]@
</code></pre>
Skip intermediate classes in hierarchy inheritance with boost::serialization
<p>Context: I have a tree-like structure representing a AST of Expr that I want to serialize using <code>boost::serialization</code>. The main issue is that all classes have non default constructors  and const children. To overcome this issue, I followed the doc and overloaded <code>load_construct_data</code> and <code>save_construct_data</code> (which end up doing all the work).</p>

<p>My question is about the <code>Mul</code> class within the code. To factorize code, I developed a template class <code>Op2</code> that is used to define operators such as <em>Add</em> or <code>Mul</code> (only <code>Mul</code> is shown here) through CRTP on these classes. In <code>Mul::serialize</code>, I directly register <code>Expr</code> as base class of <code>Mul</code>and completely skip <code>Op2</code>. <strong>The code works, valgrind is happy, but is it correct ? Or does boost::serialization require to ave the complete class hierarchy ?</strong></p>

<pre><code>#include &lt;boost/archive/text_iarchive.hpp&gt;
#include &lt;boost/archive/text_oarchive.hpp&gt;
#include &lt;boost/serialization/base_object.hpp&gt;
#include &lt;boost/serialization/export.hpp&gt;
#include &lt;boost/serialization/serialization.hpp&gt;

#include &lt;fstream&gt;
#include &lt;iomanip&gt;
#include &lt;iostream&gt;
#include &lt;map&gt;
#include &lt;memory&gt;
#include &lt;sstream&gt;
#include &lt;string&gt;
#include &lt;vector&gt;

//forward declaration of my structs
struct Expr;
struct Mul;
struct Int;

//forward declarations of custom boost functions to friend them in the class
namespace b_ser = boost::serialization;
namespace boost {
namespace serialization {

template &lt;class Archive&gt;
void load_construct_data(Archive &amp;ar, Mul *e, const unsigned int);

template &lt;class Archive&gt;
void save_construct_data(Archive &amp;ar, const Mul *a, const unsigned int);

template &lt;class Archive&gt;
void load_construct_data(Archive &amp;ar, Int *e, const unsigned int);

template &lt;class Archive&gt;
void save_construct_data(Archive &amp;ar, const Int *a, const unsigned int);


} // namespace serialization
} // namespace boost

//memory manager
std::vector&lt;std::unique_ptr&lt;Expr&gt;&gt; pool;

// AST
struct Expr {
  virtual ~Expr() {}
  virtual std::vector&lt;Expr const *&gt; children() const = 0;
  virtual std::string identity() const = 0;
  void print(int p) const {
    std::cout &lt;&lt; std::setw(p) &lt;&lt; ' ';
    std::cout &lt;&lt; identity() &lt;&lt; "\n";

    for (auto a_kid : children()) {
      a_kid-&gt;print(p + 2);
    }
  }

  void self_register() const {

    if (std::find_if(pool.begin(), pool.end(), [this](auto const &amp;stored_ptr) {
          return this == stored_ptr.get();
        }) == pool.end()) {
      pool.push_back(std::unique_ptr&lt;Expr&gt;(const_cast&lt;Expr *&gt;(this)));
    }
    for (auto ptr : children()) {
      ptr-&gt;self_register();
    }
  }
private:
friend class boost::serialization::access;
template &lt;class Archive&gt;
void serialize(Archive &amp;ar, const unsigned int version) {}

};

struct Int : Expr {
  int const n;
  std::vector&lt;Expr const *&gt; children() const override { return {}; }
  std::string identity() const override {
    return "Int[" + std::to_string(n) + "]@";
  }
  Int(int nn) : n(nn) {}

  template &lt;class Archive&gt;
  void serialize(Archive &amp;ar, const unsigned int version) {
    ar &amp;boost::serialization::base_object&lt;Expr&gt;(*this);
  }
  template &lt;class Archive&gt;
  friend void b_ser::save_construct_data(Archive &amp;ar, const Int *i,
                                         const unsigned int) {
    ar &lt;&lt; i-&gt;n;
  }
  template &lt;class Archive&gt;
  friend void b_ser::load_construct_data(Archive &amp;ar, Int *i,
                                         const unsigned int) {
    int n;
    ar &gt;&gt; n;
    ::new (i) Int(n);
  }
};

template &lt;class T&gt; struct Op2 : Expr {
  std::vector&lt;Expr const *&gt; children() const override { return {l, r}; }
  std::string identity() const override { return T::message; }
  Op2(Expr const *ll, Expr const *rr) : l(ll), r(rr) {}

protected:
  Expr const *l;
  Expr const *r;
};
struct Mul : Op2&lt;Mul&gt; {
  using Op2::Op2;
  static auto const constexpr message = "Mul";

private:
  friend class boost::serialization::access;
  template &lt;class Archive&gt;
  void serialize(Archive &amp;ar, const unsigned int version) {
    ar &amp;boost::serialization::base_object&lt;Expr&gt;(*this);
  }
  template &lt;class Archive&gt;
  friend void b_ser::save_construct_data(Archive &amp;ar, const Mul *a,
                                         const unsigned int) {
    ar &lt;&lt; a-&gt;l;
    ar &lt;&lt; a-&gt;r;
  }

  template &lt;class Archive&gt;
  friend void b_ser::load_construct_data(Archive &amp;ar, Mul *e,
                                         const unsigned int) {
    Expr *l, *r;
    ar &gt;&gt; l;
    ar &gt;&gt; r;
    ::new (e) Mul(l, r);
    e-&gt;self_register();
  }
};

template &lt;class T, class... Args&gt; T *store(Args... args) {
  auto to_store = std::make_unique&lt;T&gt;(std::forward&lt;Args&gt;(args)...);
  auto raw_ptr = to_store.get();
  pool.push_back(std::move(to_store));

  return raw_ptr;
}

BOOST_CLASS_EXPORT(Expr)
BOOST_CLASS_EXPORT(Int)
BOOST_CLASS_EXPORT(Mul)
int main(int argc, char *argv[]) {

  {

    auto deux = store&lt;Int&gt;(2);
    auto trois = store&lt;Int&gt;(3);
    auto m_23 = store&lt;Mul&gt;(trois, deux);
    auto quatre = store&lt;Int&gt;(4);

    auto root = store&lt;Mul&gt;(m_23, quatre);
    Expr *e_root = root;
    root-&gt;print(2);
    std::ofstream of("arxiv");
    boost::archive::text_oarchive oa(of);
    oa &lt;&lt; e_root;
  }
  std::cout &lt;&lt; "==================="
            &lt;&lt; "\n";
  {
    std::ifstream isf("arxiv");
    boost::archive::text_iarchive is(isf);
    Expr *expr;
    is &gt;&gt; expr;
    expr-&gt;print(2);
  }
  return 0;
}
</code></pre>