Imported Upstream version 1.49.0
[platform/upstream/boost.git] / libs / ptr_container / doc / tutorial.rst
1 ++++++++++++++++++++++++++++++++++
2  |Boost| Pointer Container Library
3 ++++++++++++++++++++++++++++++++++
4  
5 .. |Boost| image:: boost.png
6
7 ======== 
8 Tutorial 
9 ======== 
10
11 The tutorial shows you the most simple usage of the
12 library. It is assumed that the reader is familiar
13 with the use of standard containers. Although
14 the tutorial is devided into sections, it is recommended
15 that you read it all from top to bottom.
16
17 * `Basic usage`_
18 * `Indirected interface`_
19 * `Sequence containers`_
20 * `Associative containers`_
21 * `Null values`_
22 * `Cloneability`_
23 * `New functions`_
24 * `std::auto_ptr<U> overloads`_
25 * `Algorithms`_
26
27 Basic usage
28 -----------
29
30 The most important aspect of a pointer container is that it manages
31 memory for you. This means that you in most cases do not need to worry
32 about deleting memory. 
33
34 Let us assume that we have an OO-hierarchy of animals
35
36 .. parsed-literal::
37
38     class animal : `boost::noncopyable <http://www.boost.org/libs/utility/utility.htm#Class_noncopyable>`_
39     {
40     public:
41         virtual      ~animal()   {}
42         virtual void eat()       = 0;
43         virtual int  age() const = 0;
44         // ...
45     };
46     
47     class mammal : public animal
48     {
49         // ...
50     };
51     
52     class bird : public animal
53     {
54         // ...
55     };
56
57
58 Then the managing of the animals is straight-forward. Imagine a 
59 Zoo::
60
61     class zoo
62     {
63         boost::ptr_vector<animal> the_animals;
64     public:
65
66         void add_animal( animal* a )
67         {
68             the_animals.push_back( a );
69         }
70     };
71
72 Notice how we just pass the class name to the container; there
73 is no ``*`` to indicate it is a pointer.
74 With this declaration we can now say::
75     
76     zoo the_zoo;
77     the_zoo.add_animal( new mammal("joe") );
78     the_zoo.add_animal( new bird("dodo") );
79
80 Thus we heap-allocate all elements of the container
81 and never rely on copy-semantics. 
82
83 Indirected interface
84 --------------------
85
86 A particular feature of the pointer containers is that
87 the query interface is indirected. For example, ::
88
89     boost::ptr_vector<animal> vec;
90     vec.push_back( new animal ); // you add it as pointer ...
91     vec[0].eat();                // but get a reference back
92
93 This indirection also happens to iterators, so ::
94
95     typedef std::vector<animal*> std_vec;
96     std_vec vec;
97     ...
98     std_vec::iterator i = vec.begin();
99     (*i)->eat(); // '*' needed
100     
101 now becomes ::
102    
103     typedef boost::ptr_vector<animal>  ptr_vec;
104     ptr_vec vec;
105     ptr_vec::iterator i = vec.begin();
106     i->eat(); // no indirection needed
107     
108
109 Sequence containers
110 -------------------
111
112 The sequence containers are used when you do not need to
113 keep an ordering on your elements. You can basically
114 expect all operations of the normal standard containers
115 to be available. So, for example, with a  ``ptr_deque``
116 and ``ptr_list`` object you can say::
117
118     boost::ptr_deque<animal> deq;
119     deq.push_front( new animal );    
120     deq.pop_front();
121
122 because ``std::deque`` and ``std::list`` have ``push_front()``
123 and ``pop_front()`` members. 
124
125 If the standard sequence supports
126 random access, so does the pointer container; for example::
127
128     for( boost::ptr_deque<animal>::size_type i = 0u;
129          i != deq.size(); ++i )
130          deq[i].eat();
131
132 The ``ptr_vector`` also allows you to specify the size of
133 the buffer to allocate; for example ::
134
135     boost::ptr_vector<animal> animals( 10u );
136
137 will reserve room for 10 animals.              
138
139 Associative containers
140 ----------------------
141
142 To keep an ordering on our animals, we could use a ``ptr_set``::
143
144     boost::ptr_set<animal> set;
145     set.insert( new monkey("bobo") );
146     set.insert( new whale("anna") );
147     ...
148     
149 This requires that ``operator<()`` is defined for animals. One
150 way to do this could be ::
151
152     inline bool operator<( const animal& l, const animal& r )
153     {
154         return l.name() < r.name();
155     }
156     
157 if we wanted to keep the animals sorted by name.
158
159 Maybe you want to keep all the animals in zoo ordered wrt.
160 their name, but it so happens that many animals have the
161 same name. We can then use a ``ptr_multimap``::
162
163     typedef boost::ptr_multimap<std::string,animal> zoo_type;
164     zoo_type zoo;
165     std::string bobo = "bobo",
166                 anna = "anna";
167     zoo.insert( bobo, new monkey(bobo) );
168     zoo.insert( bobo, new elephant(bobo) );
169     zoo.insert( anna, new whale(anna) );
170     zoo.insert( anna, new emu(anna) );
171     
172 Note that must create the key as an lvalue 
173 (due to exception-safety issues); the following would not 
174 have compiled ::
175
176     zoo.insert( "bobo", // this is bad, but you get compile error
177                 new monkey("bobo") );
178
179 If a multimap is not needed, we can use ``operator[]()``
180 to avoid the clumsiness::
181
182     boost::ptr_map<std::string,animal> animals;
183     animals["bobo"].set_name("bobo");
184
185 This requires a default constructor for animals and
186 a function to do the initialization, in this case ``set_name()``.
187
188 A better alternative is to use `Boost.Assign <../../assign/index.html>`_
189 to help you out. In particular, consider
190
191 - `ptr_push_back(), ptr_push_front(), ptr_insert() and ptr_map_insert() <../../assign/doc/index.html#ptr_push_back>`_
192
193 - `ptr_list_of() <../../assign/doc/index.html#ptr_list_of>`_
194
195 For example, the above insertion may now be written ::
196         
197      boost::ptr_multimap<std::string,animal> animals;
198
199      using namespace boost::assign;
200      ptr_map_insert<monkey>( animals )( "bobo", "bobo" );
201      ptr_map_insert<elephant>( animals )( "bobo", "bobo" );
202      ptr_map_insert<whale>( animals )( "anna", "anna" );
203      ptr_map_insert<emu>( animals )( "anna", "anna" );
204                                         
205     
206 Null values
207 -----------
208
209 By default, if you try to insert null into a container, an exception
210 is thrown. If you want to allow nulls, then you must
211 say so explicitly when declaring the container variable ::
212
213     boost::ptr_vector< boost::nullable<animal> > animals_type;
214     animals_type animals;
215     ...
216     animals.insert( animals.end(), new dodo("fido") );
217     animals.insert( animals.begin(), 0 ) // ok
218
219 Once you have inserted a null into the container, you must
220 always check if the value is null before accessing the object ::
221
222     for( animals_type::iterator i = animals.begin();
223          i != animals.end(); ++i )
224     {
225         if( !boost::is_null(i) ) // always check for validity
226             i->eat();
227     }
228
229 If the container support random access, you may also check this as ::
230
231     for( animals_type::size_type i = 0u; 
232          i != animals.size(); ++i )
233     {
234         if( !animals.is_null(i) )
235              animals[i].eat();
236     }
237
238 Note that it is meaningless to insert
239 null into ``ptr_set`` and ``ptr_multiset``. 
240
241 Cloneability
242 ------------
243
244 In OO programming it is typical to prohibit copying of objects; the 
245 objects may sometimes be allowed to be Cloneable; for example,::
246
247     animal* animal::clone() const
248     {
249         return do_clone(); // implemented by private virtual function
250     }
251
252 If the OO hierarchy thus allows cloning, we need to tell the 
253 pointer containers how cloning is to be done. This is simply
254 done by defining a free-standing function, ``new_clone()``, 
255 in the same namespace as
256 the object hierarchy::
257
258     inline animal* new_clone( const animal& a )
259     {
260         return a.clone();
261     }
262
263 That is all, now a lot of functions in a pointer container
264 can exploit the cloneability of the animal objects. For example ::
265
266     typedef boost::ptr_list<animal> zoo_type;
267     zoo_type zoo, another_zoo;
268     ...
269     another_zoo.assign( zoo.begin(), zoo.end() );
270
271 will fill another zoo with clones of the first zoo. Similarly,
272 ``insert()`` can now insert clones into your pointer container ::
273
274     another_zoo.insert( another_zoo.begin(), zoo.begin(), zoo.end() );
275
276 The whole container can now also be cloned ::
277
278     zoo_type yet_another_zoo = zoo.clone();
279
280 Copying or assigning the container has the same effect as cloning (though it is slightly cheaper)::    
281
282     zoo_type yet_another_zoo = zoo;
283     
284 Copying also support derived-to-base class conversions::
285
286     boost::ptr_vector<monkey> monkeys = boost::assign::ptr_list_of<monkey>( "bobo" )( "bebe")( "uhuh" );
287     boost::ptr_vector<animal> animals = monkeys;
288
289 This also works for maps::
290
291     boost::ptr_map<std::string,monkey> monkeys = ...;
292     boost::ptr_map<std::string,animal> animals = monkeys;
293     
294 New functions
295 -------------
296
297 Given that we know we are working with pointers, a few new functions
298 make sense. For example, say you want to remove an
299 animal from the zoo ::
300
301     zoo_type::auto_type the_animal = zoo.release( zoo.begin() );
302     the_animal->eat();
303     animal* the_animal_ptr = the_animal.release(); // now this is not deleted
304     zoo.release(2); // for random access containers
305
306 You can think of ``auto_type`` as a non-copyable form of 
307 ``std::auto_ptr``. Notice that when you release an object, the
308 pointer is removed from the container and the containers size
309 shrinks. For containers that store nulls, we can exploit that
310 ``auto_type`` is convertible to ``bool``::
311
312     if( ptr_vector< nullable<T> >::auto_type r = vec.pop_back() )
313     {
314       ...
315     }  
316
317 You can also release the entire container if you
318 want to return it from a function ::
319
320     std::auto_ptr< boost::ptr_deque<animal> > get_zoo()
321     {
322         boost::ptr_deque<animal>  result;
323         ...
324         return result.release(); // give up ownership
325     }
326     ...
327     boost::ptr_deque<animal> animals = get_zoo();    
328
329 Let us assume we want to move an animal object from
330 one zoo to another. In other words, we want to move the 
331 animal and the responsibility of it to another zoo ::
332     
333     another_zoo.transfer( another_zoo.end(), // insert before end 
334                           zoo.begin(),       // insert this animal ...
335                           zoo );             // from this container
336     
337 This kind of "move-semantics" is different from
338 normal value-based containers. You can think of ``transfer()``
339 as the same as ``splice()`` on ``std::list``.
340
341 If you want to replace an element, you can easily do so ::
342
343     zoo_type::auto_type old_animal = zoo.replace( zoo.begin(), new monkey("bibi") ); 
344     zoo.replace( 2, old_animal.release() ); // for random access containers
345
346 A map is slightly different to iterate over than standard maps.
347 Now we say ::
348
349     typedef boost::ptr_map<std::string, boost::nullable<animal> > animal_map;
350     animal_map map;
351     ...
352     for( animal_map::const_iterator i = map.begin(), e = map.end(); i != e; ++i )
353     {
354         std::cout << "\n key: " << i->first;
355         std::cout << "\n age: ";
356         
357         if( boost::is_null(i) )
358             std::cout << "unknown";
359         else
360             std::cout << i->second->age(); 
361      }
362
363 Except for the check for null, this looks like it would with a normal map. But if ``age()`` had 
364 not been a ``const`` member function,
365 it would not have compiled.
366             
367 Maps can also be indexed with bounds-checking ::
368
369     try
370     {
371         animal& bobo = map.at("bobo");
372     }
373     catch( boost::bad_ptr_container_operation& e )
374     {
375         // "bobo" not found
376     }        
377
378 ``std::auto_ptr<U>`` overloads
379 ------------------------------
380
381 Every time there is a function that takes a ``T*`` parameter, there is
382 also a function taking an ``std::auto_ptr<U>`` parameter. This is of course done
383 to make the library intregrate seamlessly with ``std::auto_ptr``. For example ::
384
385   std::ptr_vector<Base> vec;
386   vec.push_back( new Base );
387   
388 is complemented by ::
389
390   std::auto_ptr<Derived> p( new Derived );
391   vec.push_back( p );   
392
393 Notice that the template argument for ``std::auto_ptr`` does not need to
394 follow the template argument for ``ptr_vector`` as long as ``Derived*``
395 can be implicitly converted to ``Base*``.
396
397 Algorithms
398 ----------
399
400 Unfortunately it is not possible to use pointer containers with
401 mutating algorithms from the standard library. However,
402 the most useful ones
403 are instead provided as member functions::
404
405     boost::ptr_vector<animal> zoo;
406     ...
407     zoo.sort();                               // assume 'bool operator<( const animal&, const animal& )'
408     zoo.sort( std::less<animal>() );          // the same, notice no '*' is present
409     zoo.sort( zoo.begin(), zoo.begin() + 5 ); // sort selected range
410
411 Notice that predicates are automatically wrapped in an `indirect_fun`_ object.
412
413 ..  _`indirect_fun`: indirect_fun.html
414
415 You can remove equal and adjacent elements using ``unique()``::
416    
417     zoo.unique();                             // assume 'bool operator==( const animal&, const animal& )'
418     zoo.unique( zoo.begin(), zoo.begin() + 5, my_comparison_predicate() ); 
419
420 If you just want to remove certain elements, use ``erase_if``::
421
422     zoo.erase_if( my_predicate() );
423
424 Finally you may want to merge two sorted containers::
425
426     boost::ptr_vector<animal> another_zoo = ...;
427     another_zoo.sort();                      // sorted wrt. to same order as 'zoo'
428     zoo.merge( another_zoo );
429     BOOST_ASSERT( another_zoo.empty() );    
430          
431 That is all; now you have learned all the basics!
432
433 .. raw:: html 
434
435         <hr>
436         
437 **See also**
438
439 - `Usage guidelines <guidelines.html>`_ 
440
441 - `Cast utilities <../../conversion/cast.htm#Polymorphic_castl>`_
442
443 **Navigate**
444
445 - `home <ptr_container.html>`_
446 - `examples <examples.html>`_
447
448 .. raw:: html 
449
450         <hr>
451
452 :Copyright:     Thorsten Ottosen 2004-2006. Use, modification and distribution is subject to the Boost Software License, Version 1.0 (see LICENSE_1_0.txt__).
453
454 __ http://www.boost.org/LICENSE_1_0.txt
455