Boost logo

Boost Users :

From: Robert Ramey (ramey_at_[hidden])
Date: 2007-08-22 14:22:48


I am happy to receive constructive suggestions of this nature
and want to incorporate any fixes.

I would like to see you make the following changes.

a) Eliminate the #if/#endif - which really confuses things. 1

i) just include the derived pointer part which is really
necessary. This will eliminate the #define POLYMORPHIC

ii) just include the NVP.

iii) use at typedef rather than #if ARCHIVE MODE all over the place
so that it looks like

#if ?
    #include <boost/archive/xml_oarchive.hpp>
    #include <boost/archive/xml_oarchive.hpp>
   typedef xml_oarchive output_archive_type;
   typedef xml_iarchive input_archive_type;
#else
    #include <boost/archive/text_oarchive.hpp>
    #include <boost/archive/text_oarchive.hpp>
   typedef text_oarchive output_archive_type;
   typedef text_iarchive input_archive_type;
#endif

Or even better just choose one or the other. The purpose
of the demo is to show how to use boost/serialization/shared_ptr
which is independent of which kind of archive is to be used.

b) instead of appending the comments at the end of the
code, move then into the code at the most relevant spot.

Robert Ramey

Robbie Morrison wrote:
> Hello again
>
> After posting my earlier message
> <mailman.2403.1187719362.16337.boost-users_at_[hidden]>,
> I thought some more about 'demo_shared_ptr.cpp' and
> tried new fixes (isn't that always the way).
>
> My modified file 'demo_shared_ptr.mod.cpp' now builds
> and runs cleanly in both text and XML archive modes.
>
> The revised file is appended here. It contains some
> documentation at the end which may be worth reading.
>
> Note too that the data members named 'x' are now member
> initialized and this duly silences (Linux system) g++
> compilier warnings and a raft of valgrind (memory
> checker) errors.
>
> I would now hope that a modified form of
> 'demo_shared_ptr.cpp' drawing on my experiences can be
> checked into the Boost SVN repository. I don't think I
> should be the person who does this, as I may have
> introduced subtle bugs or bad practice.
>
> Neither I have filed a bug report but would do so if
> asked.
>
> Finally, the presence of a buggy 'demo_shared_ptr.cpp'
> in both 1.33.1 and 1.34.1 almost caused me to give up
> on using Boost.Serialization. By all accounts, I am
> not the first to struggle with this demo file and
> fixing it should be accorded some priority.
>
> Many thanks, as always, to the developers and
> maintainers of Boost.Serialization!
>
> best regards to all
> Robbie
> ---
> Robbie Morrison
> PhD student -- policy-oriented energy system simulation
> Institute for Energy Engineering (IET)
> Technical University of Berlin (TU-Berlin), Germany
> [from IMAP client]
>
> // demo_shared_ptr.cpp : shows polymorphic pointer XML serialization
>
> // *******************************************************************
> // MODIFICATION WARNING: this file has been modified by a Boost user
> // and is not part of the official Boost distribution.
> // *******************************************************************
>
> // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . Polymorphic
> // derived pointer example by David Tonge. XML variant and some bug
> // fixes added by Robbie Morrison <robbie_at_[hidden]> on
> 22-Aug-2007.
>
> // Use, modification and distribution is subject to the Boost Software
> // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or
> copy at // http://www.boost.org/LICENSE_1_0.txt)
> //
> // See http://www.boost.org for updates, documentation, and revision
> history. //
> // This file has been tested with Boost release 1.34.1 dated
> // 24-Jul-2007 (source build) and release 1.33.1 (Ubuntu package)
> // using the GNU GCC 4.1.2 compiler (with -Wall -pedantic), valgrind
> // version "valgrind-3.2.0-Debian" memory checker, and Linux Ubuntu
> // 6.10 operating system (now superseded by 7.04). The file builds
> // and runs cleanly under the conditions just listed.
> //
> // Unlike the 1.34.1 version of this demo, the archive file is not
> // deleted and can be subsequently examined using any pager utility or
> // text editor.
> //
> // Jump to the end of this file for a discussion on some of the coding
> // practices employed.
>
> // ---------------------------------------------------------
> // Preprocessor directives controlling archive type
> // ---------------------------------------------------------
>
> // these can be reset lower values to aid troubleshooting
>
> // 0 = straight text, 1 = text with NVP (name-value-pair) statements,
> 2 = xml #define ARCHIVE_MODE 2
>
> // 0 = omit David Tonge derived pointer code, 1 = use derived pointer
> code #define POLYMORPHIC_CODE 1
>
> // ---------------------------------------------------------
>
> #include <iomanip> // setw() and family
> #include <iostream> // standard io
> #include <fstream> // file-based io
> #include <string> // C++ strings
>
> #include <boost/archive/tmpdir.hpp> // locate a temporary
> directory
>
> #if (ARCHIVE_MODE >= 2)
> # include <boost/archive/xml_iarchive.hpp> // archive for loading
> XML # include <boost/archive/xml_oarchive.hpp> // archive for
> saving XML #else
> # include <boost/archive/text_iarchive.hpp> // archive for loading
> text # include <boost/archive/text_oarchive.hpp> // archive for
> saving text #endif
>
> #include <boost/serialization/shared_ptr.hpp> // shared_ptr
> serialization #include <boost/serialization/base_object.hpp> // base
> class serialization #include <boost/serialization/export.hpp> //
> explicit code for exports (place last)
>
> class A
> {
> friend class boost::serialization::access;
> private:
> template <class Archive>
> void serialize
> (Archive& ar, const unsigned int class_version) {
> #if (ARCHIVE_MODE >= 1)
> ar & BOOST_SERIALIZATION_NVP(x); //
> boost::serialization::make_nvp("x", x) #else
> ar & x; // simple form for text
> archives #endif
> }
> int x;
> public:
> A(): x(42) { ++count; } // default constructor,
> the 42 is arbitrary virtual ~A() { --count; }
> static int count; // public in order to
> simplify test code };
>
> BOOST_CLASS_EXPORT(A) // requires
> <boost/serialization/export.hpp>
>
> // if using particular Metrowerks or Borland compilers, uncomment the
> following: // BOOST_SERIALIZATION_SHARED_PTR(B)
>
> int A::count = 0;
>
> class B : public A // class B added by
> David Tonge {
> friend class boost::serialization::access;
> private:
> int x;
> template<class Archive>
> void serialize(Archive& ar, const unsigned int class_version) {
> #if (ARCHIVE_MODE >= 1)
> //ar & boost::serialization::base_object<A>(*this); // CAUTION:
> problematic for XML ar &
> BOOST_SERIALIZATION_BASE_OBJECT_NVP(A); // .. but this
> works fine ar & BOOST_SERIALIZATION_NVP(x); #else
> ar & boost::serialization::base_object<A>(*this); // this is
> fine for text //ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(A);
> // .. and this also works ar & x;
> // x now saved (unlike 1.34.1) #endif
> }
> public:
> B() : A(), x(84) { ++count; } // default constructor,
> the 84 is arbitrary virtual ~B() { --count; }
> static int count;
> };
>
> // if using particular Metrowerks or Borland compilers, uncomment the
> following: // BOOST_SERIALIZATION_SHARED_PTR(B)
>
> BOOST_CLASS_EXPORT(B)
>
> int B::count = 0;
>
> void display(boost::shared_ptr<A>& a, boost::shared_ptr<A>& a1)
> {
> std::cout << "a = 0x" << std::hex << a.get() << std::dec << ", ";
> if (a.get()) std::cout << "is a " << typeid(*(a.get())).name() <<
> "*, "; std::cout << "use count = " << std::dec << a.use_count() <<
> std::endl; std::cout << "a1 = 0x" << std::hex << a1.get() <<
> std::dec << ", "; if (a1.get()) std::cout << "is a " <<
> typeid(*(a1.get())).name() << "*, "; std::cout << "use count = "
> << std::dec << a1.use_count() << std::endl; std::cout << "unique
> element count = " << A::count << std::endl; std::cout << std::endl;
> }
>
> int main(int argc, char* argv[])
> {
> // report some build details to the console
> std::cout << std::endl;
> std::cout << "archive mode : " << ARCHIVE_MODE <<
> std::endl; std::cout << "DT extension mode : " <<
> POLYMORPHIC_CODE << std::endl;
>
> // name the archive file appropriately
> #if (ARCHIVE_MODE >= 2)
> std::string ext = "xml"; // XML archive
> #else
> std::string ext = "txt"; // text archive
> #endif
>
> std::string filename(boost::archive::tmpdir()); //locate a
> temporary directory filename += "/demo_shared_ptr";
> filename += ".";
> filename += ext;
> std::cout << "testfile name : " << filename << std::endl;
> std::cout << std::endl;
>
> // note the test type
> std::cout << "base smart pointer tests" << std::endl;
> std::cout << std::endl;
>
> // create a new shared pointer to a new object of type A
> boost::shared_ptr<A> spa(new A());
> boost::shared_ptr<A> spa1;
> spa1 = spa;
> display(spa, spa1);
>
> // serialize the pointers
> {
> // open the archive file
> std::ofstream ofs(filename.c_str());
>
> #if (ARCHIVE_MODE >= 2)
> boost::archive::xml_oarchive oa(ofs);
> #else
> boost::archive::text_oarchive oa(ofs);
> #endif
>
> #if (ARCHIVE_MODE >= 1)
> oa << BOOST_SERIALIZATION_NVP(spa);
> oa << BOOST_SERIALIZATION_NVP(spa1);
> #else
> oa << spa;
> oa << spa1;
> #endif
>
> }
>
> // reset the shared pointer to NULL thereby destroying the type A
> object spa.reset();
> spa1.reset();
> display(spa, spa1);
>
> // restore state to one equivalent to the original
> {
> // open the archive file
> std::ifstream ifs(filename.c_str());
>
> #if (ARCHIVE_MODE >= 2)
> boost::archive::xml_iarchive ia(ifs);
> #else
> boost::archive::text_iarchive ia(ifs);
> #endif
>
> #if (ARCHIVE_MODE >= 1)
> ia >> BOOST_SERIALIZATION_NVP(spa);
> ia >> BOOST_SERIALIZATION_NVP(spa1);
> #else
> ia >> spa;
> ia >> spa1;
> #endif
>
> }
>
> display(spa, spa1);
> spa.reset();
> spa1.reset();
>
> #if (POLYMORPHIC_CODE >= 1) // that is, use derived
> pointer code
>
> // note the test type
> std::cout << "derived smart pointer tests" << std::endl;
> std::cout << std::endl;
>
> // new code by David Tonge starts here
>
> // create a new shared pointer to a new object of type A
> spa = boost::shared_ptr<A>(new B());
> spa1 = spa;
> display(spa, spa1);
>
> // serialize it
> // CAUTION: archive saved earlier will be simply overwritten
> {
> std::ofstream ofs(filename.c_str());
>
> #if (ARCHIVE_MODE >= 2)
> boost::archive::xml_oarchive oa(ofs);
> #else
> boost::archive::text_oarchive oa(ofs);
> #endif
>
> #if (ARCHIVE_MODE >= 1)
> oa << BOOST_SERIALIZATION_NVP(spa);
> oa << BOOST_SERIALIZATION_NVP(spa1);
> #else
> oa << spa;
> oa << spa1;
> #endif
>
> }
>
> // reset the shared pointer to NULL thereby destroying the type B
> object spa.reset();
> spa1.reset();
> display(spa, spa1);
>
> // restore state to one equivalent to the original
> {
> // reopen the archive
> std::ifstream ifs(filename.c_str());
>
> #if (ARCHIVE_MODE >= 2)
> boost::archive::xml_iarchive ia(ifs);
> #else
> boost::archive::text_iarchive ia(ifs);
> #endif
>
> #if (ARCHIVE_MODE >= 1)
> ia >> BOOST_SERIALIZATION_NVP(spa);
> ia >> BOOST_SERIALIZATION_NVP(spa1);
> #else
> ia >> spa;
> ia >> spa1;
> #endif
>
> }
>
> display(spa, spa1);
>
> #endif // POLYMORPHIC_CODE
>
> return 0;
> } // main()
>
> // ---------------------------------
> // Output
> // ---------------------------------
> //
> // archive mode : 2
> // DT extension mode : 1
> // testfile name : ./demo_shared_ptr.xml
> //
> // base smart pointer tests
> //
> // a = 0x0x42ca428, is a 1A*, use count = 2
> // a1 = 0x0x42ca428, is a 1A*, use count = 2
> // unique element count = 1
> //
> // a = 0x0, use count = 0
> // a1 = 0x0, use count = 0
> // unique element count = 0
> //
> // a = 0x0x42d3a08, is a 1A*, use count = 2
> // a1 = 0x0x42d3a08, is a 1A*, use count = 2
> // unique element count = 1
> //
> // derived smart pointer tests
> //
> // a = 0x0x42d4ab0, is a 1B*, use count = 2
> // a1 = 0x0x42d4ab0, is a 1B*, use count = 2
> // unique element count = 1
> //
> // a = 0x0, use count = 0
> // a1 = 0x0, use count = 0
> // unique element count = 0
> //
> // a = 0x0x42de180, is a 1B*, use count = 2
> // a1 = 0x0x42de180, is a 1B*, use count = 2
> // unique element count = 1
>
> // ---------------------------------
> // Coding practices
> // ---------------------------------
> //
> // Polymorphic behavior
> //
> // This demo does involve polymorphic behavior due to the
> // presence of a virtual function in the base class, in this case
> // the virtual destructor for A:
> //
> // virtual ~A(); // gives rise to polymorphic behavior
> //
> // If you wish to experiment, remove the virtual specifier and
> // note the now much reduced XML archive.
> //
> // Default (zero-argument) constructor
> //
> // All deserialized classes need a default constructor. This
> // need not be explicitly defined, in which case the
> // compiler-supplied version is used. For deserialization
> // purposes, the default constructor can be private (although
> // other design considerations will normally mean that it is, at
> // most, protected).
> //
> // Class registration
> //
> // In this demo, class registration relies on explicit export of
> // the class and its globally unique identifier (GUID). This is
> // achieved using the following macro:
> //
> // BOOST_CLASS_EXPORT(Class) // "Class" becomes the GUID
> //
> // This form of class registration is known as "key export". A
> // more general macro also exists (but was not employed here) in
> // which the client code actively manages the GUID:
> //
> // BOOST_CLASS_EXPORT_GUID(Class, "my-guid")
> //
> // Class registration can also be accomplished by inserting a C++
> // registration statement within 'serialize' or, in some cases,
> // placing reliance on serialization order. However these other
> // approaches require an up-front knowledge of the class
> // hierarchy or are dependent on program flow. Key export is
> // hence the more flexible and less brittle strategy and should
> // therefore be preferred. Moreover, it is probably good
> // practice to explicitly export all serialized classes, even
> when // this is not strictly required.
> //
> // Base/derived information
> //
> // Class hierarchy information is communicated here using the
> // following macro:
> //
> // ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(BaseClass);
> //
> // As before, a direct C++ statement is possible. However this
> // broke for the XML format archive (I didn't investigate why).
> // Hence it would appear that use of the above macro is necessary
> // when serializing to XML.
> //
> // Non-default names/GUIDs
> //
> // If a macro which employs an explicit object name or class GUID
> // is used, then the new string literal must be valid XML. In
> // particular, whitespace is not acceptable and its use will
> // generate an "unrecognized XML syntax" exception at run-time:
> //
> // using boost::serialization::make_nvp;
> // ar & make_nvp("my data", data); // run-time exception
> //
> // Associated headers
> //
> // Read the code itself for more information on the associated
> // headers and their correct placement:
> //
> // <boost/serialization/base_object.hpp>
> // <boost/serialization/export.hpp>
> //
> // Build and run command-lines (your library name may be different)
> //
> // all warnings (the grep screening relates to -Weffc++, see man
> g++): //
> // $ g++ -ggdb -Wall -Weffc++ -pedantic
> // demo_shared_ptr.mod.cpp
> // -lboost_serialization-gcc41
> // -o demo_shared_ptr
> // 2>&1
> // | grep --invert-match
> '/usr/local/include/boost-1_34_1/boost' // | grep
> --invert-match 'instantiated from' //
> // simplified build:
> //
> // $ g++ demo_shared_ptr.mod.cpp
> // -lboost_serialization-gcc41
> // -o demo_shared_ptr
> //
> // run with memory checking:
> //
> // $ valgrind ./demo_shared_ptr
> //
> // simplified run:
> //
> // $ ./demo_shared_ptr
> //
> // Compile-time static asserts
> //
> // These may be difficult to interpret (in my limited
> // experience). Note that a pointer to a C++ fundamental type
> // (for example, int*) cannot be de/serialized.
> //
> // Run-time exceptions
> //
> // Some common messages and probable fixes (based on the style
> // recommendations above):
> //
> // "unregistered_class"
> // missing: BOOST_CLASS_EXPORT(SubClass)
> //
> // "unregistered void cast"
> // missing: ar &
> BOOST_SERIALIZATION_BASE_OBJECT_NVP(BaseClass); //
> // "unrecognized XML syntax"
> // name-value-pair name contains whitespace
>
> // end of file demo_shared_ptr.mod.cpp


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