Boost logo

Boost Users :

Subject: [Boost-users] [Serialization] XML serialization of class with abstract template ancestors
From: Terry Roberts (terryr_at_[hidden])
Date: 2009-10-29 18:17:30


Hi,

I'm having some trouble using the Serialization library with a class derived
from an abstract template (example code below). What I'd like to do is
serialize instances of the derived type through a base class pointer
(polymorphic) using the XML archive. The code below works fine using both
the text and binary archives, but fails at runtime with the XML archive.
The exception thrown is boost::archive::xml_archive_exception with the
message "uninitialized exception".

My environment:
GCC 4.1.2 on RHEL 5.3
Boost v1.37

I've also attempted to use Boost 1.40 (although I didn't see anything to
suggest relevant changes), which results in link errors (undefined
references to members of
boost::archive::detail::archive_serializer_map<boost::archive::xml_iarchive>
and boost::serialization::void_cast_detail::void_caster among others).

Any help would be appreciated. Thanks.

#include <iostream>
#include <string>
#include <sstream>
#include <boost/serialization/serialization.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/export.hpp>

class AbstractBase
{
public:
  AbstractBase(const std::string& n):name(n) {}
  virtual ~AbstractBase() {}

  virtual std::ostream& print(std::ostream& os) const = 0;

protected:
  AbstractBase():name("UNKNOWN BASE") {}

  friend class boost::serialization::access;
  template<class Archive> void serialize(Archive& ar, const uint32_t
version)
  {
    ar & BOOST_SERIALIZATION_NVP(name);
  }

  std::string name;
};

template <class T>
class AbstractTemplate : public AbstractBase
{
public:
  AbstractTemplate(const std::string& n):AbstractBase(n) {}
  virtual ~AbstractTemplate() {}

  virtual void doSomething(const T& t) = 0;

protected:
  AbstractTemplate():AbstractBase("UKNOWN TEMPLATE") {}

  friend class boost::serialization::access;
  template<class Archive> void serialize(Archive& ar, const uint32_t
version)
  {
    ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(AbstractBase);
  }
};

class Derived : public AbstractTemplate<std::string>
{
public:
  Derived(const std::string& n):AbstractTemplate<std::string>(n) {}
  virtual ~Derived() {}

  std::ostream& print(std::ostream& os) const { return os << "Derived name:
" << name << std::endl; }

  void doSomething(const std::string& str) { print(std::cout << str << ":
"); }

protected:
  Derived():AbstractTemplate<std::string>("UNKNOWN DERIVED") {}

  friend class boost::serialization::access;
  template<class Archive> void serialize(Archive& ar, const uint32_t
version)
  {
    ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(AbstractTemplate<std::string>);
  }
};

BOOST_CLASS_EXPORT(Derived)

namespace boost {

template <>
struct is_abstract<AbstractBase >
{
  typedef mpl::bool_<true> type;
  BOOST_STATIC_CONSTANT(bool, value = true);
};

template<class T>
struct is_abstract<AbstractTemplate<T> >
{
  typedef mpl::bool_<true> type;
  BOOST_STATIC_CONSTANT(bool, value = true);
};

} // namepsace boost

int main(int argc, char** argv)
{
  static const char XML_NAME[] = "Stuff";

  Derived* d = new Derived("test 1");
  AbstractTemplate<std::string>* at = d;
  AbstractBase* ab = d;

  std::cout << "before serialization:" << std::endl;
  d->doSomething("something");
  at->print(std::cout);
  ab->print(std::cout);

  /* serialization */
  std::stringstream ss;

  {
    boost::archive::xml_oarchive xmlOut(ss);
    xmlOut << boost::serialization::make_nvp(XML_NAME, ab);
  }

  delete ab;
  ab = NULL;

  std::cout << "Serialization:" << std::endl
        << ss.str() << std::endl;

  /* deserialization */
  {
    boost::archive::xml_iarchive xmlIn(ss);
    xmlIn >> boost::serialization::make_nvp(XML_NAME, ab);
  }

  at = dynamic_cast<AbstractTemplate<std::string>*>(ab);
  d = dynamic_cast<Derived*>(ab);

  if ((ab == NULL)
    || (at == NULL)
    || (d == NULL))
  {
    std::cout << "deserialization failed" << std::endl;
    return EXIT_FAILURE;
  }

  std::cout << "after deserialization:" << std::endl;
  d->doSomething("something");
  at->print(std::cout);
  ab->print(std::cout);
  delete ab;

  return EXIT_SUCCESS;
}



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net