summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/serialization/example/demo_exception.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/serialization/example/demo_exception.cpp')
-rw-r--r--src/boost/libs/serialization/example/demo_exception.cpp258
1 files changed, 258 insertions, 0 deletions
diff --git a/src/boost/libs/serialization/example/demo_exception.cpp b/src/boost/libs/serialization/example/demo_exception.cpp
new file mode 100644
index 000000000..84f881f9b
--- /dev/null
+++ b/src/boost/libs/serialization/example/demo_exception.cpp
@@ -0,0 +1,258 @@
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// demo_exception.cpp
+
+// (C) Copyright 2002-4 Robert Ramey - http://www.rrsd.com .
+// 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)
+
+// Example of safe exception handling for pointer de-serialization
+//
+// This example was prepared by Robert Ramey to demonstrate and test
+// safe exception handling during the de-serialization of pointers in
+// a non-trivial example.
+//
+// Hopefully, this addresses exception issues raised by
+// Vahan Margaryan who spent considerable time and effort
+// in the analysis and testing of issues of exception safety
+// of the serialization library.
+
+#include <algorithm>
+#include <iostream>
+#include <cstddef> // NULL
+#include <fstream>
+#include <string>
+
+#include <cstdio> // remove
+#include <boost/config.hpp>
+#if defined(BOOST_NO_STDC_NAMESPACE)
+namespace std{
+ using ::remove;
+}
+#endif
+
+#include <boost/archive/tmpdir.hpp>
+
+#ifndef BOOST_NO_EXCEPTIONS
+#include <exception>
+#endif
+
+#include <boost/archive/text_iarchive.hpp>
+#include <boost/archive/text_oarchive.hpp>
+
+#include <boost/serialization/list.hpp>
+#include <boost/serialization/split_member.hpp>
+
+template<class TPTR>
+struct deleter
+{
+ void operator()(TPTR t){
+ delete t;
+ }
+};
+
+class Course;
+class Student;
+
+class Student
+{
+public:
+ static int count;
+ Student(){
+ count++;
+ }
+ ~Student(){
+ some_courses.clear();
+ count--;
+ }
+ std::list<Course *> some_courses;
+private:
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* file_version */){
+ ar & some_courses;
+ }
+};
+
+int Student::count = 0;
+
+class Course
+{
+public:
+ static int count;
+ Course(){
+ count++;
+ }
+ ~Course(){
+ // doesnt delete pointers in list
+ // since it doesn't "own" them
+ some_students.clear();
+ count--;
+ }
+ std::list<Student *> some_students;
+private:
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int /* file_version */){
+ ar & some_students;
+ }
+};
+
+int Course::count = 0;
+
+class School
+{
+public:
+ ~School(){
+ // must delete all the students because
+ // it "owns" them
+ std::for_each(all_students.begin(), all_students.end(), deleter<Student *>());
+ all_students.clear();
+ // as well as courses
+ std::for_each(all_courses.begin(), all_courses.end(), deleter<Course *>());
+ all_courses.clear();
+ }
+ std::list<Student *> all_students;
+ std::list<Course *> all_courses;
+private:
+ friend class boost::serialization::access;
+ BOOST_SERIALIZATION_SPLIT_MEMBER()
+ template<class Archive>
+ void save(Archive & ar, const unsigned int file_version) const;
+ template<class Archive>
+ void load(Archive & ar, const unsigned int file_version);
+};
+
+#if 0
+// case 1:
+template<class Archive>
+void School::serialize(Archive & ar, const unsigned int /* file_version */){
+ // if an exeception occurs while loading courses
+ // the structure courses may have some courses each
+ // with students
+ ar & all_courses;
+ // while all_students will have no members.
+ ar & all_students; // create students that have no courses
+ // so ~School() will delete all members of courses
+ // but this will NOT delete any students - see above
+ // a memory leak will be the result.
+}
+
+// switching the order of serialization doesn't help in this case
+// case 2:
+template<class Archive>
+void School::serialize(Archive & ar, const unsigned int /* file_version */){
+ ar & all_students;
+ ar >> all_courses; // create any courses that have no students
+}
+#endif
+
+template<class Archive>
+void School::save(Archive & ar, const unsigned int /* file_version */) const {
+ ar << all_students;
+ ar << all_courses;
+}
+
+template<class Archive>
+void School::load(Archive & ar, const unsigned int /* file_version */){
+ // if an exeception occurs while loading courses
+ // the structure courses may have some courses each
+ // with students
+ try{
+ // deserialization of a Course * will in general provoke the
+ // deserialization of Student * which are added to the list of
+ // students for a class. That is, this process will result
+ // in the copying of a pointer.
+ ar >> all_courses;
+ ar >> all_students; // create students that have no courses
+ }
+ catch(std::exception){
+ // elminate any dangling references
+ all_courses.clear();
+ all_students.clear();
+ throw;
+ }
+}
+
+void init(School *school){
+ Student *bob = new Student();
+ Student *ted = new Student();
+ Student *carol = new Student();
+ Student *alice = new Student();
+
+ school->all_students.push_back(bob);
+ school->all_students.push_back(ted);
+ school->all_students.push_back(carol);
+ school->all_students.push_back(alice);
+
+ Course *math = new Course();
+ Course *history = new Course();
+ Course *literature = new Course();
+ Course *gym = new Course();
+
+ school->all_courses.push_back(math);
+ school->all_courses.push_back(history);
+ school->all_courses.push_back(literature);
+ school->all_courses.push_back(gym);
+
+ bob->some_courses.push_back(math);
+ math->some_students.push_back(bob);
+ bob->some_courses.push_back(literature);
+ literature->some_students.push_back(bob);
+
+ ted->some_courses.push_back(math);
+ math->some_students.push_back(ted);
+ ted->some_courses.push_back(history);
+ history->some_students.push_back(ted);
+
+ alice->some_courses.push_back(literature);
+ literature->some_students.push_back(alice);
+ alice->some_courses.push_back(history);
+ history->some_students.push_back(alice);
+
+ // no students signed up for gym
+ // carol has no courses
+}
+
+void save(const School * const school, const char *filename){
+ std::ofstream ofile(filename);
+ boost::archive::text_oarchive ar(ofile);
+ ar << school;
+}
+
+void load(School * & school, const char *filename){
+ std::ifstream ifile(filename);
+ boost::archive::text_iarchive ar(ifile);
+ try{
+ ar >> school;
+ }
+ catch(std::exception){
+ // eliminate dangling reference
+ school = NULL;
+ }
+}
+
+int main(int argc, char *argv[]){
+ std::string filename(boost::archive::tmpdir());
+ filename += "/demofile.txt";
+
+ School *school = new School();
+ std::cout << "1. student count = " << Student::count << std::endl;
+ std::cout << "2. class count = " << Course::count << std::endl;
+ init(school);
+ std::cout << "3. student count = " << Student::count << std::endl;
+ std::cout << "4. class count = " << Course::count << std::endl;
+ save(school, filename.c_str());
+ delete school;
+ school = NULL;
+ std::cout << "5. student count = " << Student::count << std::endl;
+ std::cout << "6. class count = " << Course::count << std::endl;
+ load(school, filename.c_str());
+ std::cout << "7. student count = " << Student::count << std::endl;
+ std::cout << "8. class count = " << Course::count << std::endl;
+ delete school;
+ std::cout << "9. student count = " << Student::count << std::endl;
+ std::cout << "10. class count = " << Course::count << std::endl;
+ std::remove(filename.c_str());
+ return Student::count + Course::count;
+}