Re: [Boost-users] serialization lib, demo_shared_ptr.cpp, XML archives
Hello again
After posting my earlier message
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
Hello again
After posting my earlier message
, 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
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
// locate a temporary directory #if (ARCHIVE_MODE >= 2) # include
// archive for loading XML # include // archive for saving XML #else # include // archive for loading text # include // archive for saving text #endif #include
// shared_ptr serialization #include // base class serialization #include // 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
// 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: // //
// // // 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
participants (2)
-
Robbie Morrison
-
Robert Ramey