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

source code of boost/libs/ptr_container/test/tut1.cpp