]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/ptr_container/doc/tutorial.rst
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / 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