• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
40 class animal : boost::noncopyable
41 {
42     virtual std::string do_speak() const = 0;
43     std::string name_;
44 
45 protected:
46     //
47     // Animals cannot be copied...
48     //
animal(const animal & r)49     animal( const animal& r ) : name_( r.name_ )           { }
50     void operator=( const animal& );
51 
52 private:
53     //
54     // ...but due to advances in genetics, we can clone them!
55     //
56 
57     virtual animal* do_clone() const = 0;
58 
59 public:
animal(const std::string & name)60     animal( const std::string& name ) : name_(name)        { }
~animal()61     virtual ~animal() throw()                              { }
62 
speak() const63     std::string speak() const
64     {
65         return do_speak();
66     }
67 
name() const68     std::string name() const
69     {
70         return name_;
71     }
72 
clone() const73     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 
new_clone(const animal & a)86 animal* 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 
96 const std::string muuuh = "Muuuh!";
97 const std::string oiink = "Oiiink";
98 
99 class cow : public animal
100 {
do_speak() const101     virtual std::string do_speak() const
102     {
103         return muuuh;
104     }
105 
do_clone() const106     virtual animal* do_clone() const
107     {
108         return new cow( *this );
109     }
110 
111 public:
cow(const std::string & name)112     cow( const std::string& name ) : animal(name)          { }
113 };
114 
115 class pig : public animal
116 {
do_speak() const117     virtual std::string do_speak() const
118     {
119         return oiink;
120     }
121 
do_clone() const122     virtual animal* do_clone() const
123     {
124         return new pig( *this );
125     }
126 
127 public:
pig(const std::string & name)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 
136 class 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 
155 public:
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     //
farm()184     farm()                                                 { }
185 
186     //
187     // We need a constructor that can make a new
188     // farm by cloning a range of animals.
189     //
farm(animal_iterator begin,animal_iterator end)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 
begin()204     animal_iterator begin()
205     {
206         return barn.begin();
207     }
208 
end()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     //
buy_animal(animal * a)219     void buy_animal( animal* a )
220     {
221         barn.push_back( a );
222     }
223 
224     //
225     // The farm can also be in economical trouble and
226     // therefore be in the need to sell animals.
227     //
sell_animal(animal_iterator to_sell)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( to_sell );
240     }
241 
242     //
243     // How big a farm do we have?
244     //
size() const245     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     //
sell_farm()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 
buy_farm(raii_ptr other)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( 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
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 
main()285 int 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( 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 );
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( 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( new_farm.sell_farm() );
356 
357     BOOST_ASSERT( new_farm.size()    == 0u );
358     BOOST_ASSERT( animal_farm.size() == 12u );
359 }
360