diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
commit | e6918187568dbd01842d8d1d2c808ce16a894239 (patch) | |
tree | 64f88b554b444a49f656b6c656111a145cbbaa28 /src/boost/libs/serialization/example/demo_exception.cpp | |
parent | Initial commit. (diff) | |
download | ceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip |
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/serialization/example/demo_exception.cpp')
-rw-r--r-- | src/boost/libs/serialization/example/demo_exception.cpp | 258 |
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; +} |