Ticket #3730: test_diamond2.cpp

File test_diamond2.cpp, 6.4 KB (added by Barry Searle <barry.searle@…>, 13 years ago)

example program to reproduce problem

Line 
1/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
2// test_diamond.cpp
3
4// (C) Copyright 2002-2009 Vladimir Prus and Robert Ramey.
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// test of serialization library for diamond inheritence situations
10
11#include <cstddef> // NULL
12#include <fstream>
13#include <iostream>
14
15#include <boost/config.hpp>
16#include <cstdio> // remove
17#if defined(BOOST_NO_STDC_NAMESPACE)
18namespace std{
19 using ::remove;
20}
21#endif
22
23#include "test_tools.hpp"
24
25#include <boost/serialization/map.hpp>
26#include <boost/serialization/utility.hpp>
27#include <boost/serialization/split_member.hpp>
28#include <boost/serialization/tracking.hpp>
29#include <boost/serialization/base_object.hpp>
30#include <boost/serialization/nvp.hpp>
31#include <boost/serialization/export.hpp>
32
33int save_count = 0; // used to detect when base class is saved multiple times
34int load_count = 0; // used to detect when base class is loaded multiple times
35
36class base {
37public:
38 base() : i(0) {}
39 base(int i) : i(i)
40 {
41 m[i] = "text";
42 }
43
44 virtual void method1() = 0;
45
46 template<class Archive>
47 void save(Archive &ar, const unsigned int /* file_version */) const
48 {
49 std::cout << "Saving base\n";
50 ar << BOOST_SERIALIZATION_NVP(i);
51 ar << BOOST_SERIALIZATION_NVP(m);
52 ++save_count;
53 }
54
55 template<class Archive>
56 void load(Archive & ar, const unsigned int /* file_version */)
57 {
58 std::cout << "Restoring base\n";
59 ar >> BOOST_SERIALIZATION_NVP(i);
60 ar >> BOOST_SERIALIZATION_NVP(m);
61 ++load_count;
62 }
63
64 BOOST_SERIALIZATION_SPLIT_MEMBER()
65
66 bool operator==(const base& another) const
67 {
68 return i == another.i && m == another.m;
69 }
70 // make polymorphic by marking at least one function virtual
71 virtual ~base() {};
72private:
73 int i;
74 std::map<int, std::string> m;
75};
76
77// note: the default is for object tracking to be performed if and only
78// if and object of the corresponding class is anywhere serialized
79// through a pointer. In this example, that doesn't occur so
80// by default, the shared base object wouldn't normally be tracked.
81// This would leave to multiple save/load operation of the data in
82// this shared base class. This wouldn't cause an error, but it would
83// be a waste of time. So set the tracking behavior trait of the base
84// class to always track serialized objects of that class. This permits
85// the system to detect and elminate redundent save/load operations.
86// (It is concievable that this might someday be detected automatically
87// but for now, this is not done so we have to rely on the programmer
88// to specify this trait)
89BOOST_CLASS_TRACKING(base, track_always)
90
91class derived1 : virtual public base {
92public:
93 template<class Archive>
94 void save(Archive &ar, const unsigned int /* file_version */) const
95 {
96 std::cout << "Saving derived1\n";
97 ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(base);
98 }
99
100 template<class Archive>
101 void load(Archive & ar, const unsigned int /* file_version */)
102 {
103 std::cout << "Restoring derived1\n";
104 ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(base);
105 }
106
107 BOOST_SERIALIZATION_SPLIT_MEMBER()
108};
109
110class derived2 : virtual public base {
111public:
112 template<class Archive>
113 void save(Archive &ar, const unsigned int /* file_version */) const
114 {
115 std::cout << "Saving derived2\n";
116 ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(base);
117 }
118
119 template<class Archive>
120 void load(Archive & ar, const unsigned int /* file_version */)
121 {
122 std::cout << "Restoring derived2\n";
123 ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(base);
124 }
125
126 BOOST_SERIALIZATION_SPLIT_MEMBER()
127};
128
129class intermediate : public derived1, public derived2 {
130public:
131 intermediate() {}
132 intermediate(int i) : base(i) {}
133
134 void method1();
135
136 template<class Archive>
137 void save(Archive &ar, const unsigned int /* file_version */) const
138 {
139 std::cout << "Saving intermediate\n";
140 ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(derived1);
141 ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(derived2);
142 }
143
144 template<class Archive>
145 void load(Archive & ar, const unsigned int /* file_version */)
146 {
147 std::cout << "Restoring intermediate\n";
148 ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(derived1);
149 ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(derived2);
150 }
151
152 BOOST_SERIALIZATION_SPLIT_MEMBER()
153};
154
155class final : public intermediate {
156public:
157 final() {}
158 final(int i) : base(i) {}
159
160 template<class Archive>
161 void save(Archive &ar, const unsigned int /* file_version */) const
162 {
163 std::cout << "Saving final\n";
164 ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(intermediate);
165 }
166
167 template<class Archive>
168 void load(Archive & ar, const unsigned int /* file_version */)
169 {
170 std::cout << "Restoring final\n";
171 ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(intermediate);
172 }
173
174 BOOST_SERIALIZATION_SPLIT_MEMBER()
175};
176
177BOOST_CLASS_EXPORT(final)
178
179void intermediate::method1()
180{
181}
182
183int
184test_main( int /* argc */, char* /* argv */[] )
185{
186 const char * testfile = boost::archive::tmpnam(NULL);
187 BOOST_REQUIRE(NULL != testfile);
188
189 const final b(3);
190 {
191 test_ostream ofs(testfile, TEST_STREAM_FLAGS);
192 test_oarchive oa(ofs);
193 oa << boost::serialization::make_nvp("b", b);
194 }
195
196 final b2;
197 {
198 test_istream ifs(testfile, TEST_STREAM_FLAGS);
199 test_iarchive ia(ifs);
200 ia >> boost::serialization::make_nvp("b2", b2);
201 }
202 BOOST_CHECK(1 == save_count);
203 BOOST_CHECK(1 == load_count);
204 BOOST_CHECK(b2 == b);
205 std::remove(testfile);
206
207 // do the same test with pointers
208 testfile = boost::archive::tmpnam(NULL);
209 BOOST_REQUIRE(NULL != testfile);
210
211 save_count = 0;
212 load_count = 0;
213
214 const base* bp = new final( 3 );
215 {
216 test_ostream ofs(testfile);
217 test_oarchive oa(ofs);
218 oa << BOOST_SERIALIZATION_NVP(bp);
219 }
220
221 base* bp2;
222 {
223 test_istream ifs(testfile);
224 test_iarchive ia(ifs);
225 ia >> BOOST_SERIALIZATION_NVP(bp2);
226 }
227
228 BOOST_CHECK(1 == save_count);
229 BOOST_CHECK(1 == load_count);
230 BOOST_CHECK(*bp2 == *bp);
231 std::remove(testfile);
232
233 return EXIT_SUCCESS;
234}