[Serialization] XML serialization of class with abstract template ancestors

View: New views
3 Messages — Rating Filter:   Alert me  

[Serialization] XML serialization of class with abstract template ancestors

by Terry Roberts-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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 mailing list
Boost-users@...
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Re: [Serialization] XML serialization of class withabstract template ancestors

by Robert Ramey :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Some parts of this message have been removed. Learn more about Nabble's security policy.
I would be very suspicious of
 
BOOST_SERIALIZATION_BASE_OBJECT_NVP(AbstractTemplate<std::string>)
 
since the "name" is taken from the argument. Look at this macro definition and
expand it by hand. 
 
If you car run under the debugger that would also indicate the call tree which
would be useful.
 
Robert Ramey
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 mailing list
Boost-users@...
http://lists.boost.org/mailman/listinfo.cgi/boost-users

_______________________________________________
Boost-users mailing list
Boost-users@...
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Re: [Serialization] XML serialization of class with abstract template ancestors

by Terry Roberts-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Some parts of this message have been removed. Learn more about Nabble's security policy.
Robert Ramey wrote:
I would be very suspicious of
 
BOOST_SERIALIZATION_BASE_OBJECT_NVP(AbstractTemplate<std::string>)
 
since the "name" is taken from the argument. Look at this macro definition and
expand it by hand.
That was it!  I had previously made the substitution, but mistakenly included the '<', '>' and ':' anyway.  Replacing the macro in Derived::serialize() with the expansion below solves the problem.

ar & boost::serialization::make_nvp("AbstractTemplateString",
                                                       boost::serialization::base_object<AbstractTemplate<std::string> >(*this));

Thanks a ton!


_______________________________________________
Boost-users mailing list
Boost-users@...
http://lists.boost.org/mailman/listinfo.cgi/boost-users