sl@0
|
1 |
//
|
sl@0
|
2 |
// Boost.Pointer Container
|
sl@0
|
3 |
//
|
sl@0
|
4 |
// Copyright Thorsten Ottosen 2003-2005. Use, modification and
|
sl@0
|
5 |
// distribution is subject to the Boost Software License, Version
|
sl@0
|
6 |
// 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
sl@0
|
7 |
// http://www.boost.org/LICENSE_1_0.txt)
|
sl@0
|
8 |
//
|
sl@0
|
9 |
// For more information, see http://www.boost.org/libs/ptr_container/
|
sl@0
|
10 |
//
|
sl@0
|
11 |
|
sl@0
|
12 |
//
|
sl@0
|
13 |
// This example is intended to get you started.
|
sl@0
|
14 |
// Notice how the smart container
|
sl@0
|
15 |
//
|
sl@0
|
16 |
// 1. takes ownership of objects
|
sl@0
|
17 |
// 2. transfers ownership
|
sl@0
|
18 |
// 3. applies indirection to iterators
|
sl@0
|
19 |
// 4. clones objects from other smart containers
|
sl@0
|
20 |
//
|
sl@0
|
21 |
|
sl@0
|
22 |
//
|
sl@0
|
23 |
// First we select which container to use.
|
sl@0
|
24 |
//
|
sl@0
|
25 |
#include <boost/ptr_container/ptr_deque.hpp>
|
sl@0
|
26 |
|
sl@0
|
27 |
//
|
sl@0
|
28 |
// we need these later in the example
|
sl@0
|
29 |
//
|
sl@0
|
30 |
#include <boost/assert.hpp>
|
sl@0
|
31 |
#include <string>
|
sl@0
|
32 |
#include <exception>
|
sl@0
|
33 |
|
sl@0
|
34 |
|
sl@0
|
35 |
//
|
sl@0
|
36 |
// Then we define a small polymorphic class
|
sl@0
|
37 |
// hierarchy.
|
sl@0
|
38 |
//
|
sl@0
|
39 |
|
sl@0
|
40 |
class animal : boost::noncopyable
|
sl@0
|
41 |
{
|
sl@0
|
42 |
virtual std::string do_speak() const = 0;
|
sl@0
|
43 |
std::string name_;
|
sl@0
|
44 |
|
sl@0
|
45 |
protected:
|
sl@0
|
46 |
//
|
sl@0
|
47 |
// Animals cannot be copied...
|
sl@0
|
48 |
//
|
sl@0
|
49 |
animal( const animal& r ) : name_( r.name_ ) { }
|
sl@0
|
50 |
void operator=( const animal& );
|
sl@0
|
51 |
|
sl@0
|
52 |
private:
|
sl@0
|
53 |
//
|
sl@0
|
54 |
// ...but due to advances in genetics, we can clone them!
|
sl@0
|
55 |
//
|
sl@0
|
56 |
|
sl@0
|
57 |
virtual animal* do_clone() const = 0;
|
sl@0
|
58 |
|
sl@0
|
59 |
public:
|
sl@0
|
60 |
animal( const std::string& name ) : name_(name) { }
|
sl@0
|
61 |
virtual ~animal() throw() { }
|
sl@0
|
62 |
|
sl@0
|
63 |
std::string speak() const
|
sl@0
|
64 |
{
|
sl@0
|
65 |
return do_speak();
|
sl@0
|
66 |
}
|
sl@0
|
67 |
|
sl@0
|
68 |
std::string name() const
|
sl@0
|
69 |
{
|
sl@0
|
70 |
return name_;
|
sl@0
|
71 |
}
|
sl@0
|
72 |
|
sl@0
|
73 |
animal* clone() const
|
sl@0
|
74 |
{
|
sl@0
|
75 |
return do_clone();
|
sl@0
|
76 |
}
|
sl@0
|
77 |
};
|
sl@0
|
78 |
|
sl@0
|
79 |
//
|
sl@0
|
80 |
// An animal is still not Clonable. We need this last hook.
|
sl@0
|
81 |
//
|
sl@0
|
82 |
// Notice that we pass the animal by const reference
|
sl@0
|
83 |
// and return by pointer.
|
sl@0
|
84 |
//
|
sl@0
|
85 |
|
sl@0
|
86 |
animal* new_clone( const animal& a )
|
sl@0
|
87 |
{
|
sl@0
|
88 |
return a.clone();
|
sl@0
|
89 |
}
|
sl@0
|
90 |
|
sl@0
|
91 |
//
|
sl@0
|
92 |
// We do not need to define 'delete_clone()' since
|
sl@0
|
93 |
// since the default is to call the default 'operator delete()'.
|
sl@0
|
94 |
//
|
sl@0
|
95 |
|
sl@0
|
96 |
const std::string muuuh = "Muuuh!";
|
sl@0
|
97 |
const std::string oiink = "Oiiink";
|
sl@0
|
98 |
|
sl@0
|
99 |
class cow : public animal
|
sl@0
|
100 |
{
|
sl@0
|
101 |
virtual std::string do_speak() const
|
sl@0
|
102 |
{
|
sl@0
|
103 |
return muuuh;
|
sl@0
|
104 |
}
|
sl@0
|
105 |
|
sl@0
|
106 |
virtual animal* do_clone() const
|
sl@0
|
107 |
{
|
sl@0
|
108 |
return new cow( *this );
|
sl@0
|
109 |
}
|
sl@0
|
110 |
|
sl@0
|
111 |
public:
|
sl@0
|
112 |
cow( const std::string& name ) : animal(name) { }
|
sl@0
|
113 |
};
|
sl@0
|
114 |
|
sl@0
|
115 |
class pig : public animal
|
sl@0
|
116 |
{
|
sl@0
|
117 |
virtual std::string do_speak() const
|
sl@0
|
118 |
{
|
sl@0
|
119 |
return oiink;
|
sl@0
|
120 |
}
|
sl@0
|
121 |
|
sl@0
|
122 |
virtual animal* do_clone() const
|
sl@0
|
123 |
{
|
sl@0
|
124 |
return new pig( *this );
|
sl@0
|
125 |
}
|
sl@0
|
126 |
|
sl@0
|
127 |
public:
|
sl@0
|
128 |
pig( const std::string& name ) : animal(name) { }
|
sl@0
|
129 |
};
|
sl@0
|
130 |
|
sl@0
|
131 |
//
|
sl@0
|
132 |
// Then we, of course, need a place to put all
|
sl@0
|
133 |
// those animals.
|
sl@0
|
134 |
//
|
sl@0
|
135 |
|
sl@0
|
136 |
class farm
|
sl@0
|
137 |
{
|
sl@0
|
138 |
//
|
sl@0
|
139 |
// This is where the smart containers are handy
|
sl@0
|
140 |
//
|
sl@0
|
141 |
typedef boost::ptr_deque<animal> barn_type;
|
sl@0
|
142 |
barn_type barn;
|
sl@0
|
143 |
|
sl@0
|
144 |
//
|
sl@0
|
145 |
// An error type
|
sl@0
|
146 |
//
|
sl@0
|
147 |
struct farm_trouble : public std::exception { };
|
sl@0
|
148 |
|
sl@0
|
149 |
public:
|
sl@0
|
150 |
//
|
sl@0
|
151 |
// We would like to make it possible to
|
sl@0
|
152 |
// iterate over the animals in the farm
|
sl@0
|
153 |
//
|
sl@0
|
154 |
typedef barn_type::iterator animal_iterator;
|
sl@0
|
155 |
|
sl@0
|
156 |
//
|
sl@0
|
157 |
// We also need to count the farm's size...
|
sl@0
|
158 |
//
|
sl@0
|
159 |
typedef barn_type::size_type size_type;
|
sl@0
|
160 |
|
sl@0
|
161 |
//
|
sl@0
|
162 |
// And we also want to transfer an animal
|
sl@0
|
163 |
// safely around. The easiest way to think
|
sl@0
|
164 |
// about '::auto_type' is to imagine a simplified
|
sl@0
|
165 |
// 'std::auto_ptr<T>' ... this means you can expect
|
sl@0
|
166 |
//
|
sl@0
|
167 |
// T* operator->()
|
sl@0
|
168 |
// T* release()
|
sl@0
|
169 |
// deleting destructor
|
sl@0
|
170 |
//
|
sl@0
|
171 |
// but not more.
|
sl@0
|
172 |
//
|
sl@0
|
173 |
typedef barn_type::auto_type animal_transport;
|
sl@0
|
174 |
|
sl@0
|
175 |
//
|
sl@0
|
176 |
// Create an empty farm.
|
sl@0
|
177 |
//
|
sl@0
|
178 |
farm() { }
|
sl@0
|
179 |
|
sl@0
|
180 |
//
|
sl@0
|
181 |
// We need a constructor that can make a new
|
sl@0
|
182 |
// farm by cloning a range of animals.
|
sl@0
|
183 |
//
|
sl@0
|
184 |
farm( animal_iterator begin, animal_iterator end )
|
sl@0
|
185 |
:
|
sl@0
|
186 |
//
|
sl@0
|
187 |
// Objects are always cloned before insertion
|
sl@0
|
188 |
// unless we explicitly add a pointer or
|
sl@0
|
189 |
// use 'release()'. Therefore we actually
|
sl@0
|
190 |
// clone all animals in the range
|
sl@0
|
191 |
//
|
sl@0
|
192 |
barn( begin, end ) { }
|
sl@0
|
193 |
|
sl@0
|
194 |
//
|
sl@0
|
195 |
// ... so we need some other function too
|
sl@0
|
196 |
//
|
sl@0
|
197 |
|
sl@0
|
198 |
animal_iterator begin()
|
sl@0
|
199 |
{
|
sl@0
|
200 |
return barn.begin();
|
sl@0
|
201 |
}
|
sl@0
|
202 |
|
sl@0
|
203 |
animal_iterator end()
|
sl@0
|
204 |
{
|
sl@0
|
205 |
return barn.end();
|
sl@0
|
206 |
}
|
sl@0
|
207 |
|
sl@0
|
208 |
//
|
sl@0
|
209 |
// Here it is quite ok to have an 'animal*' argument.
|
sl@0
|
210 |
// The smart container will handle all ownership
|
sl@0
|
211 |
// issues.
|
sl@0
|
212 |
//
|
sl@0
|
213 |
void buy_animal( animal* a )
|
sl@0
|
214 |
{
|
sl@0
|
215 |
barn.push_back( a );
|
sl@0
|
216 |
}
|
sl@0
|
217 |
|
sl@0
|
218 |
//
|
sl@0
|
219 |
// The farm can also be in economical trouble and
|
sl@0
|
220 |
// therefore be in the need to sell animals.
|
sl@0
|
221 |
//
|
sl@0
|
222 |
animal_transport sell_animal( animal_iterator to_sell )
|
sl@0
|
223 |
{
|
sl@0
|
224 |
if( to_sell == end() )
|
sl@0
|
225 |
throw farm_trouble();
|
sl@0
|
226 |
|
sl@0
|
227 |
//
|
sl@0
|
228 |
// Here we remove the animal from the barn,
|
sl@0
|
229 |
// but the animal is not deleted yet...it's
|
sl@0
|
230 |
// up to the buyer to decide what
|
sl@0
|
231 |
// to do with it.
|
sl@0
|
232 |
//
|
sl@0
|
233 |
return barn.release( to_sell );
|
sl@0
|
234 |
}
|
sl@0
|
235 |
|
sl@0
|
236 |
//
|
sl@0
|
237 |
// How big a farm do we have?
|
sl@0
|
238 |
//
|
sl@0
|
239 |
size_type size() const
|
sl@0
|
240 |
{
|
sl@0
|
241 |
return barn.size();
|
sl@0
|
242 |
}
|
sl@0
|
243 |
|
sl@0
|
244 |
//
|
sl@0
|
245 |
// If things are bad, we might choose to sell all animals :-(
|
sl@0
|
246 |
//
|
sl@0
|
247 |
std::auto_ptr<barn_type> sell_farm()
|
sl@0
|
248 |
{
|
sl@0
|
249 |
return barn.release();
|
sl@0
|
250 |
}
|
sl@0
|
251 |
|
sl@0
|
252 |
//
|
sl@0
|
253 |
// However, if things are good, we might buy somebody
|
sl@0
|
254 |
// else's farm :-)
|
sl@0
|
255 |
//
|
sl@0
|
256 |
|
sl@0
|
257 |
void buy_farm( std::auto_ptr<barn_type> other )
|
sl@0
|
258 |
{
|
sl@0
|
259 |
//
|
sl@0
|
260 |
// This line inserts all the animals from 'other'
|
sl@0
|
261 |
// and is guaranteed either to succeed or to have no
|
sl@0
|
262 |
// effect
|
sl@0
|
263 |
//
|
sl@0
|
264 |
barn.transfer( barn.end(), // insert new animals at the end
|
sl@0
|
265 |
*other ); // we want to transfer all animals,
|
sl@0
|
266 |
// so we use the whole container as argument
|
sl@0
|
267 |
//
|
sl@0
|
268 |
// You might think you would have to do
|
sl@0
|
269 |
//
|
sl@0
|
270 |
// other.release();
|
sl@0
|
271 |
//
|
sl@0
|
272 |
// but '*other' is empty and can go out of scope as it wants
|
sl@0
|
273 |
//
|
sl@0
|
274 |
BOOST_ASSERT( other->empty() );
|
sl@0
|
275 |
}
|
sl@0
|
276 |
|
sl@0
|
277 |
}; // class 'farm'.
|
sl@0
|
278 |
|
sl@0
|
279 |
#include <boost/test/included/test_exec_monitor.hpp>
|
sl@0
|
280 |
int test_main(int,char *[])
|
sl@0
|
281 |
{
|
sl@0
|
282 |
//
|
sl@0
|
283 |
// First we make a farm
|
sl@0
|
284 |
//
|
sl@0
|
285 |
farm animal_farm;
|
sl@0
|
286 |
BOOST_ASSERT( animal_farm.size() == 0u );
|
sl@0
|
287 |
|
sl@0
|
288 |
animal_farm.buy_animal( new pig("Betty") );
|
sl@0
|
289 |
animal_farm.buy_animal( new pig("Benny") );
|
sl@0
|
290 |
animal_farm.buy_animal( new pig("Jeltzin") );
|
sl@0
|
291 |
animal_farm.buy_animal( new cow("Hanz") );
|
sl@0
|
292 |
animal_farm.buy_animal( new cow("Mary") );
|
sl@0
|
293 |
animal_farm.buy_animal( new cow("Frederik") );
|
sl@0
|
294 |
BOOST_ASSERT( animal_farm.size() == 6u );
|
sl@0
|
295 |
|
sl@0
|
296 |
//
|
sl@0
|
297 |
// Then we make another farm...it will actually contain
|
sl@0
|
298 |
// a clone of the other farm.
|
sl@0
|
299 |
//
|
sl@0
|
300 |
farm new_farm( animal_farm.begin(), animal_farm.end() );
|
sl@0
|
301 |
BOOST_ASSERT( new_farm.size() == 6u );
|
sl@0
|
302 |
|
sl@0
|
303 |
//
|
sl@0
|
304 |
// Is it really clones in the new farm?
|
sl@0
|
305 |
//
|
sl@0
|
306 |
BOOST_ASSERT( new_farm.begin()->name() == "Betty" );
|
sl@0
|
307 |
|
sl@0
|
308 |
//
|
sl@0
|
309 |
// Then we search for an animal, Mary (the Crown Princess of Denmark),
|
sl@0
|
310 |
// because we would like to buy her ...
|
sl@0
|
311 |
//
|
sl@0
|
312 |
typedef farm::animal_iterator iterator;
|
sl@0
|
313 |
iterator to_sell;
|
sl@0
|
314 |
for( iterator i = animal_farm.begin(),
|
sl@0
|
315 |
end = animal_farm.end();
|
sl@0
|
316 |
i != end; ++i )
|
sl@0
|
317 |
{
|
sl@0
|
318 |
if( i->name() == "Mary" )
|
sl@0
|
319 |
{
|
sl@0
|
320 |
to_sell = i;
|
sl@0
|
321 |
break;
|
sl@0
|
322 |
}
|
sl@0
|
323 |
}
|
sl@0
|
324 |
|
sl@0
|
325 |
farm::animal_transport mary = animal_farm.sell_animal( to_sell );
|
sl@0
|
326 |
|
sl@0
|
327 |
|
sl@0
|
328 |
if( mary->speak() == muuuh )
|
sl@0
|
329 |
//
|
sl@0
|
330 |
// Great, Mary is a cow, and she may live longer
|
sl@0
|
331 |
//
|
sl@0
|
332 |
new_farm.buy_animal( mary.release() );
|
sl@0
|
333 |
else
|
sl@0
|
334 |
//
|
sl@0
|
335 |
// Then the animal would be destroyed (!)
|
sl@0
|
336 |
// when we go out of scope.
|
sl@0
|
337 |
//
|
sl@0
|
338 |
;
|
sl@0
|
339 |
|
sl@0
|
340 |
//
|
sl@0
|
341 |
// Now we can observe some changes to the two farms...
|
sl@0
|
342 |
//
|
sl@0
|
343 |
BOOST_ASSERT( animal_farm.size() == 5u );
|
sl@0
|
344 |
BOOST_ASSERT( new_farm.size() == 7u );
|
sl@0
|
345 |
|
sl@0
|
346 |
//
|
sl@0
|
347 |
// The new farm has however underestimated how much
|
sl@0
|
348 |
// it cost to feed Mary and its owner is forced to sell the farm...
|
sl@0
|
349 |
//
|
sl@0
|
350 |
animal_farm.buy_farm( new_farm.sell_farm() );
|
sl@0
|
351 |
|
sl@0
|
352 |
BOOST_ASSERT( new_farm.size() == 0u );
|
sl@0
|
353 |
BOOST_ASSERT( animal_farm.size() == 12u );
|
sl@0
|
354 |
return 0;
|
sl@0
|
355 |
}
|