Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_33_1/libs/ptr_container/test/tut1.cpp @ 12

Last change on this file since 12 was 12, checked in by landauf, 17 years ago

added boost

  • Property svn:executable set to *
File size: 7.9 KB
Line 
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    //
145    // An error type
146    //
147    struct farm_trouble : public std::exception           { };
148
149public:
150    //
151    // We would like to make it possible to
152    // iterate over the animals in the farm
153    //
154    typedef barn_type::iterator  animal_iterator;
155
156    //
157    // We also need to count the farm's size...
158    //
159    typedef barn_type::size_type size_type;
160   
161    //
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
166    //
167    //   T* operator->()
168    //   T* release()
169    //   deleting destructor
170    //
171    // but not more.
172    //
173    typedef barn_type::auto_type  animal_transport;
174
175    //
176    // Create an empty farm.
177    //
178    farm()                                                 { }
179   
180    //
181    // We need a constructor that can make a new
182    // farm by cloning a range of animals.
183    //
184    farm( animal_iterator begin, animal_iterator end )
185     : 
186        //
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
191        //
192        barn( begin, end )                               { }
193   
194    //
195    // ... so we need some other function too
196    //
197
198    animal_iterator begin()
199    {
200        return barn.begin();
201    }
202
203    animal_iterator end()
204    {
205        return barn.end();
206    }
207   
208    //
209    // Here it is quite ok to have an 'animal*' argument.
210    // The smart container will handle all ownership
211    // issues.
212    //
213    void buy_animal( animal* a )
214    {
215        barn.push_back( a );
216    }
217
218    //
219    // The farm can also be in economical trouble and
220    // therefore be in the need to sell animals.
221    //
222    animal_transport sell_animal( animal_iterator to_sell )
223    {
224        if( to_sell == end() )
225            throw farm_trouble();
226
227        //
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
231        // to do with it.
232        //
233        return barn.release( to_sell );
234    }
235
236    //
237    // How big a farm do we have?
238    //
239    size_type size() const
240    {
241        return barn.size();
242    }
243
244    //
245    // If things are bad, we might choose to sell all animals :-(
246    //
247    std::auto_ptr<barn_type> sell_farm()
248    {
249        return barn.release();
250    }
251
252    //
253    // However, if things are good, we might buy somebody
254    // else's farm :-)
255    //
256
257    void buy_farm( std::auto_ptr<barn_type> other )
258    {
259        //
260        // This line inserts all the animals from 'other'
261        // and is guaranteed either to succeed or to have no
262        // effect
263        //
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
267        //
268        // You might think you would have to do
269        //
270        // other.release();
271        //
272        // but '*other' is empty and can go out of scope as it wants
273        //
274        BOOST_ASSERT( other->empty() );
275    }
276   
277}; // class 'farm'.
278
279int main()
280{
281    //
282    // First we make a farm
283    //
284    farm animal_farm;
285    BOOST_ASSERT( animal_farm.size() == 0u );
286   
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 );
294
295    //
296    // Then we make another farm...it will actually contain
297    // a clone of the other farm.
298    //
299    farm new_farm( animal_farm.begin(), animal_farm.end() );
300    BOOST_ASSERT( new_farm.size() == 6u );
301
302    //
303    // Is it really clones in the new farm?
304    //
305    BOOST_ASSERT( new_farm.begin()->name() == "Betty" );
306   
307    //
308    // Then we search for an animal, Mary (the Crown Princess of Denmark),
309    // because we would like to buy her ...
310    //
311    typedef farm::animal_iterator iterator;
312    iterator to_sell;
313    for( iterator i   = animal_farm.begin(),
314                  end = animal_farm.end();
315         i != end; ++i )
316    {
317        if( i->name() == "Mary" )
318        {
319            to_sell = i;
320            break;
321        }
322    }
323
324    farm::animal_transport mary = animal_farm.sell_animal( to_sell );
325
326
327    if( mary->speak() == muuuh )
328        //
329        // Great, Mary is a cow, and she may live longer
330        //
331        new_farm.buy_animal( mary.release() );
332    else
333        //
334        // Then the animal would be destroyed (!)
335        // when we go out of scope.
336        //
337        ;
338
339    //
340    // Now we can observe some changes to the two farms...
341    //
342    BOOST_ASSERT( animal_farm.size() == 5u );
343    BOOST_ASSERT( new_farm.size()    == 7u );
344
345    //
346    // The new farm has however underestimated how much
347    // it cost to feed Mary and its owner is forced to sell the farm...
348    //
349    animal_farm.buy_farm( new_farm.sell_farm() );
350
351    BOOST_ASSERT( new_farm.size()    == 0u );
352    BOOST_ASSERT( animal_farm.size() == 12u );     
353}
Note: See TracBrowser for help on using the repository browser.