2 // Boost.Pointer Container
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)
9 // For more information, see http://www.boost.org/libs/ptr_container/
13 // This example is intended to get you started.
14 // Notice how the smart container
16 // 1. takes ownership of objects
17 // 2. transfers ownership
18 // 3. applies indirection to iterators
19 // 4. clones objects from other smart containers
23 // First we select which container to use.
25 #include <boost/ptr_container/ptr_deque.hpp>
28 // we need these later in the example
30 #include <boost/assert.hpp>
36 // Then we define a small polymorphic class
40 class animal
: boost::noncopyable
42 virtual std::string
do_speak() const = 0;
47 // Animals cannot be copied...
49 animal( const animal
& r
) : name_( r
.name_
) { }
50 void operator=( const animal
& );
54 // ...but due to advances in genetics, we can clone them!
57 virtual animal
* do_clone() const = 0;
60 animal( const std::string
& name
) : name_(name
) { }
61 virtual ~animal() throw() { }
63 std::string
speak() const
68 std::string
name() const
80 // An animal is still not Clonable. We need this last hook.
82 // Notice that we pass the animal by const reference
83 // and return by pointer.
86 animal
* new_clone( const animal
& a
)
92 // We do not need to define 'delete_clone()' since
93 // since the default is to call the default 'operator delete()'.
96 const std::string muuuh
= "Muuuh!";
97 const std::string oiink
= "Oiiink";
99 class cow
: public animal
101 virtual std::string
do_speak() const
106 virtual animal
* do_clone() const
108 return new cow( *this );
112 cow( const std::string
& name
) : animal(name
) { }
115 class pig
: public animal
117 virtual std::string
do_speak() const
122 virtual animal
* do_clone() const
124 return new pig( *this );
128 pig( const std::string
& name
) : animal(name
) { }
132 // Then we, of course, need a place to put all
139 // This is where the smart containers are handy
141 typedef boost::ptr_deque
<animal
> barn_type
;
147 struct farm_trouble
: public std::exception
{ };
151 // We would like to make it possible to
152 // iterate over the animals in the farm
154 typedef barn_type::iterator animal_iterator
;
157 // We also need to count the farm's size...
159 typedef barn_type::size_type size_type
;
162 // And we also want to transfer an animal
163 // safely around. The easiest way to think
164 // about '::auto_type' is to imagine a simplified
165 // 'std::auto_ptr<T>' ... this means you can expect
169 // deleting destructor
173 typedef barn_type::auto_type animal_transport
;
176 // Create an empty farm.
181 // We need a constructor that can make a new
182 // farm by cloning a range of animals.
184 farm( animal_iterator begin
, animal_iterator end
)
187 // Objects are always cloned before insertion
188 // unless we explicitly add a pointer or
189 // use 'release()'. Therefore we actually
190 // clone all animals in the range
192 barn( begin
, end
) { }
195 // ... so we need some other function too
198 animal_iterator
begin()
203 animal_iterator
end()
209 // Here it is quite ok to have an 'animal*' argument.
210 // The smart container will handle all ownership
213 void buy_animal( animal
* a
)
219 // The farm can also be in economical trouble and
220 // therefore be in the need to sell animals.
222 animal_transport
sell_animal( animal_iterator to_sell
)
224 if( to_sell
== end() )
225 throw farm_trouble();
228 // Here we remove the animal from the barn,
229 // but the animal is not deleted yet...it's
230 // up to the buyer to decide what
233 return barn
.release( to_sell
);
237 // How big a farm do we have?
239 size_type
size() const
245 // If things are bad, we might choose to sell all animals :-(
247 std::auto_ptr
<barn_type
> sell_farm()
249 return barn
.release();
253 // However, if things are good, we might buy somebody
257 void buy_farm( std::auto_ptr
<barn_type
> other
)
260 // This line inserts all the animals from 'other'
261 // and is guaranteed either to succeed or to have no
264 barn
.transfer( barn
.end(), // insert new animals at the end
265 *other
); // we want to transfer all animals,
266 // so we use the whole container as argument
268 // You might think you would have to do
272 // but '*other' is empty and can go out of scope as it wants
274 BOOST_ASSERT( other
->empty() );
282 // First we make a farm
285 BOOST_ASSERT( animal_farm
.size() == 0u );
287 animal_farm
.buy_animal( new pig("Betty") );
288 animal_farm
.buy_animal( new pig("Benny") );
289 animal_farm
.buy_animal( new pig("Jeltzin") );
290 animal_farm
.buy_animal( new cow("Hanz") );
291 animal_farm
.buy_animal( new cow("Mary") );
292 animal_farm
.buy_animal( new cow("Frederik") );
293 BOOST_ASSERT( animal_farm
.size() == 6u );
296 // Then we make another farm...it will actually contain
297 // a clone of the other farm.
299 farm
new_farm( animal_farm
.begin(), animal_farm
.end() );
300 BOOST_ASSERT( new_farm
.size() == 6u );
303 // Is it really clones in the new farm?
305 BOOST_ASSERT( new_farm
.begin()->name() == "Betty" );
308 // Then we search for an animal, Mary (the Crown Princess of Denmark),
309 // because we would like to buy her ...
311 typedef farm::animal_iterator iterator
;
313 for( iterator i
= animal_farm
.begin(),
314 end
= animal_farm
.end();
317 if( i
->name() == "Mary" )
324 farm::animal_transport mary
= animal_farm
.sell_animal( to_sell
);
327 if( mary
->speak() == muuuh
)
329 // Great, Mary is a cow, and she may live longer
331 new_farm
.buy_animal( mary
.release() );
334 // Then the animal would be destroyed (!)
335 // when we go out of scope.
340 // Now we can observe some changes to the two farms...
342 BOOST_ASSERT( animal_farm
.size() == 5u );
343 BOOST_ASSERT( new_farm
.size() == 7u );
346 // The new farm has however underestimated how much
347 // it cost to feed Mary and its owner is forced to sell the farm...
349 animal_farm
.buy_farm( new_farm
.sell_farm() );
351 BOOST_ASSERT( new_farm
.size() == 0u );
352 BOOST_ASSERT( animal_farm
.size() == 12u );