Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/serialization/example/demo_exception.cpp @ 29

Last change on this file since 29 was 29, checked in by landauf, 17 years ago

updated boost from 1_33_1 to 1_34_1

File size: 7.3 KB
Line 
1/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
2// demo_exception.cpp
3
4// (C) Copyright 2002-4 Robert Ramey - http://www.rrsd.com .
5// Use, modification and distribution is subject to the Boost Software
6// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt)
8
9// Example of safe exception handling for pointer de-serialization
10//
11// This example was prepared by Robert Ramey to demonstrate and test
12// safe exception handling during the de-serialization of pointers in
13// a non-trivial example.
14//
15// Hopefully, this addresses exception issues raised by
16// Vahan Margaryan who spent considerable time and effort
17// in the analysis and testing of issues of exception safety
18// of the serialization library.
19
20#include <algorithm>
21#include <iostream>
22#include <fstream>
23#include <string>
24
25#include <cstdio> // remove
26#include <boost/config.hpp>
27#if defined(BOOST_NO_STDC_NAMESPACE)
28namespace std{ 
29    using ::remove;
30}
31#endif
32
33#include <boost/archive/tmpdir.hpp>
34
35#ifndef BOOST_NO_EXCEPTIONS
36#include <exception>
37#endif
38
39#include <boost/archive/text_iarchive.hpp>
40#include <boost/archive/text_oarchive.hpp>
41
42#include <boost/serialization/list.hpp>
43#include <boost/serialization/split_member.hpp>
44
45template<class TPTR>
46struct deleter
47{
48    void operator()(TPTR t){
49        delete t;
50    }
51};
52
53class Course;
54class Student;
55
56class Student
57{
58public:
59    static int count;
60    Student(){
61        count++;
62    }
63    ~Student(){
64        some_courses.clear();
65        count--;
66    }
67    std::list<Course *> some_courses;
68private:
69    friend class boost::serialization::access;
70    template<class Archive>
71    void serialize(Archive & ar, const unsigned int /* file_version */){
72        ar & some_courses;
73    }
74};
75
76int Student::count = 0;
77
78class Course
79{
80public:
81    static int count;
82    Course(){
83        count++;
84    }
85    ~Course(){
86        // doesnt delete pointers in list
87        // since it doesn't "own" them
88        some_students.clear();
89        count--;
90    }
91    std::list<Student *> some_students;
92private:
93    friend class boost::serialization::access;
94    template<class Archive>
95    void serialize(Archive & ar, const unsigned int /* file_version */){
96        ar & some_students;
97    }
98};
99
100int Course::count = 0;
101
102class School
103{
104public:
105    ~School(){
106        // must delete all the students because
107        // it "owns" them
108        std::for_each(all_students.begin(), all_students.end(), deleter<Student *>());
109        all_students.clear();
110        // as well as courses
111        std::for_each(all_courses.begin(), all_courses.end(), deleter<Course *>());
112        all_courses.clear();
113    }
114    std::list<Student *> all_students;
115    std::list<Course *> all_courses;
116private:
117    friend class boost::serialization::access;
118    BOOST_SERIALIZATION_SPLIT_MEMBER()
119    template<class Archive>
120    void save(Archive & ar, const unsigned int file_version) const;
121    template<class Archive>
122    void load(Archive & ar, const unsigned int file_version);
123};
124
125#if 0
126// case 1:
127template<class Archive>
128void School::serialize(Archive & ar, const unsigned int /* file_version */){
129    // if an exeception occurs while loading courses
130    // the structure courses may have some courses each
131    // with students
132    ar & all_courses;
133    // while all_students will have no members.
134    ar & all_students; // create students that have no courses
135    // so ~School() will delete all members of courses
136    // but this will NOT delete any students - see above
137    // a memory leak will be the result.
138}
139
140// switching the order of serialization doesn't help in this case
141// case 2:
142template<class Archive>
143void School::serialize(Archive & ar, const unsigned int /* file_version */){
144    ar & all_students;
145    ar >> all_courses;  // create any courses that have no students
146}
147#endif
148
149template<class Archive>
150void School::save(Archive & ar, const unsigned int /* file_version */) const {
151    ar << all_students;
152    ar << all_courses;
153}
154
155template<class Archive>
156void School::load(Archive & ar, const unsigned int /* file_version */){
157    // if an exeception occurs while loading courses
158    // the structure courses may have some courses each
159    // with students
160    try{
161        // deserialization of a Course * will in general provoke the
162        // deserialization of Student * which are added to the list of
163        // students for a class.  That is, this process will result
164        // in the copying of a pointer.
165        ar >> all_courses;
166        ar >> all_students; // create students that have no courses
167    }
168    catch(std::exception){
169        // elminate any dangling references
170        all_courses.clear();
171        all_students.clear();
172        throw;
173    }
174}
175
176void init(School *school){
177    Student *bob = new Student();
178    Student *ted = new Student();
179    Student *carol = new Student();
180    Student *alice = new Student();
181
182    school->all_students.push_back(bob);
183    school->all_students.push_back(ted);
184    school->all_students.push_back(carol);
185    school->all_students.push_back(alice);
186
187    Course *math = new Course();
188    Course *history = new Course();
189    Course *literature = new Course();
190    Course *gym = new Course();
191
192    school->all_courses.push_back(math);
193    school->all_courses.push_back(history);
194    school->all_courses.push_back(literature);
195    school->all_courses.push_back(gym);
196
197    bob->some_courses.push_back(math);
198    math->some_students.push_back(bob);
199    bob->some_courses.push_back(literature);
200    literature->some_students.push_back(bob);
201
202    ted->some_courses.push_back(math);
203    math->some_students.push_back(ted);
204    ted->some_courses.push_back(history);
205    history->some_students.push_back(ted);
206
207    alice->some_courses.push_back(literature);
208    literature->some_students.push_back(alice);
209    alice->some_courses.push_back(history);
210    history->some_students.push_back(alice);
211
212    // no students signed up for gym
213    // carol has no courses
214}
215
216void save(const School * const school, const char *filename){
217    std::ofstream ofile(filename);
218    boost::archive::text_oarchive ar(ofile);
219    ar << school;
220}
221
222void load(School * & school, const char *filename){
223    std::ifstream ifile(filename);
224    boost::archive::text_iarchive ar(ifile);
225    try{
226        ar >> school;
227    }
228    catch(std::exception){
229        // eliminate dangling reference
230        school = NULL;
231    }
232}
233
234int main(int argc, char *argv[]){
235    std::string filename(boost::archive::tmpdir());
236    filename += "/demofile.txt";
237
238    School *school = new School();
239    std::cout << "1. student count = " << Student::count << std::endl;
240    std::cout << "2. class count = " << Course::count << std::endl;
241    init(school);
242    std::cout << "3. student count = " << Student::count << std::endl;
243    std::cout << "4. class count = " << Course::count << std::endl;
244    save(school, filename.c_str());
245    delete school;
246    school = NULL;
247    std::cout << "5. student count = " << Student::count << std::endl;
248    std::cout << "6. class count = " << Course::count << std::endl;
249    load(school, filename.c_str());
250    std::cout << "7. student count = " << Student::count << std::endl;
251    std::cout << "8. class count = " << Course::count << std::endl;
252    delete school;
253    std::cout << "9. student count = " << Student::count << std::endl;
254    std::cout << "10. class count = " << Course::count << std::endl;
255    std::remove(filename.c_str());
256    return Student::count + Course::count;
257}
Note: See TracBrowser for help on using the repository browser.