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
;
144 #if !defined(BOOST_NO_CXX11_SMART_PTR) && !(defined(BOOST_MSVC) && BOOST_MSVC == 1600)
145 typedef std::unique_ptr
<barn_type
> raii_ptr
;
147 typedef std::auto_ptr
<barn_type
> raii_ptr
;
153 struct farm_trouble
: public std::exception
{ };
157 // We would like to make it possible to
158 // iterate over the animals in the farm
160 typedef barn_type::iterator animal_iterator
;
163 // We also need to count the farm's size...
165 typedef barn_type::size_type size_type
;
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
175 // deleting destructor
179 typedef barn_type::auto_type animal_transport
;
182 // Create an empty farm.
187 // We need a constructor that can make a new
188 // farm by cloning a range of animals.
190 farm( animal_iterator begin
, animal_iterator end
)
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
198 barn( begin
, end
) { }
201 // ... so we need some other function too
204 animal_iterator
begin()
209 animal_iterator
end()
215 // Here it is quite ok to have an 'animal*' argument.
216 // The smart container will handle all ownership
219 void buy_animal( animal
* a
)
225 // The farm can also be in economical trouble and
226 // therefore be in the need to sell animals.
228 animal_transport
sell_animal( animal_iterator to_sell
)
230 if( to_sell
== end() )
231 throw farm_trouble();
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
239 return barn
.release( to_sell
);
243 // How big a farm do we have?
245 size_type
size() const
251 // If things are bad, we might choose to sell all animals :-(
255 return barn
.release();
259 // However, if things are good, we might buy somebody
263 void buy_farm( raii_ptr other
)
266 // This line inserts all the animals from 'other'
267 // and is guaranteed either to succeed or to have no
270 barn
.transfer( barn
.end(), // insert new animals at the end
271 *other
); // we want to transfer all animals,
272 // so we use the whole container as argument
274 // You might think you would have to do
278 // but '*other' is empty and can go out of scope as it wants
280 BOOST_ASSERT( other
->empty() );
288 // First we make a farm
291 BOOST_ASSERT( animal_farm
.size() == 0u );
293 animal_farm
.buy_animal( new pig("Betty") );
294 animal_farm
.buy_animal( new pig("Benny") );
295 animal_farm
.buy_animal( new pig("Jeltzin") );
296 animal_farm
.buy_animal( new cow("Hanz") );
297 animal_farm
.buy_animal( new cow("Mary") );
298 animal_farm
.buy_animal( new cow("Frederik") );
299 BOOST_ASSERT( animal_farm
.size() == 6u );
302 // Then we make another farm...it will actually contain
303 // a clone of the other farm.
305 farm
new_farm( animal_farm
.begin(), animal_farm
.end() );
306 BOOST_ASSERT( new_farm
.size() == 6u );
309 // Is it really clones in the new farm?
311 BOOST_ASSERT( new_farm
.begin()->name() == "Betty" );
314 // Then we search for an animal, Mary (the Crown Princess of Denmark),
315 // because we would like to buy her ...
317 typedef farm::animal_iterator iterator
;
319 for( iterator i
= animal_farm
.begin(),
320 end
= animal_farm
.end();
323 if( i
->name() == "Mary" )
330 farm::animal_transport mary
= animal_farm
.sell_animal( to_sell
);
333 if( mary
->speak() == muuuh
)
335 // Great, Mary is a cow, and she may live longer
337 new_farm
.buy_animal( mary
.release() );
340 // Then the animal would be destroyed (!)
341 // when we go out of scope.
346 // Now we can observe some changes to the two farms...
348 BOOST_ASSERT( animal_farm
.size() == 5u );
349 BOOST_ASSERT( new_farm
.size() == 7u );
352 // The new farm has however underestimated how much
353 // it cost to feed Mary and its owner is forced to sell the farm...
355 animal_farm
.buy_farm( new_farm
.sell_farm() );
357 BOOST_ASSERT( new_farm
.size() == 0u );
358 BOOST_ASSERT( animal_farm
.size() == 12u );