]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/ptr_container/doc/tutorial.rst
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / ptr_container / doc / tutorial.rst
CommitLineData
7c673cae
FG
1++++++++++++++++++++++++++++++++++
2 |Boost| Pointer Container Library
3++++++++++++++++++++++++++++++++++
4
5.. |Boost| image:: boost.png
6
7========
8Tutorial
9========
10
11The tutorial shows you the most simple usage of the
12library. It is assumed that the reader is familiar
13with the use of standard containers. Although
14the tutorial is devided into sections, it is recommended
15that 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
27Basic usage
28-----------
29
30The most important aspect of a pointer container is that it manages
31memory for you. This means that you in most cases do not need to worry
32about deleting memory.
33
34Let 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
58Then the managing of the animals is straight-forward. Imagine a
59Zoo::
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
72Notice how we just pass the class name to the container; there
73is no ``*`` to indicate it is a pointer.
74With 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
80Thus we heap-allocate all elements of the container
81and never rely on copy-semantics.
82
83Indirected interface
84--------------------
85
86A particular feature of the pointer containers is that
87the 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
93This 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
101now 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
109Sequence containers
110-------------------
111
112The sequence containers are used when you do not need to
113keep an ordering on your elements. You can basically
114expect all operations of the normal standard containers
115to be available. So, for example, with a ``ptr_deque``
116and ``ptr_list`` object you can say::
117
118 boost::ptr_deque<animal> deq;
119 deq.push_front( new animal );
120 deq.pop_front();
121
122because ``std::deque`` and ``std::list`` have ``push_front()``
123and ``pop_front()`` members.
124
125If the standard sequence supports
126random 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
132The ``ptr_vector`` also allows you to specify the size of
133the buffer to allocate; for example ::
134
135 boost::ptr_vector<animal> animals( 10u );
136
137will reserve room for 10 animals.
138
139Associative containers
140----------------------
141
142To 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
149This requires that ``operator<()`` is defined for animals. One
150way 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
157if we wanted to keep the animals sorted by name.
158
159Maybe you want to keep all the animals in zoo ordered wrt.
160their name, but it so happens that many animals have the
161same 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
172Note that must create the key as an lvalue
173(due to exception-safety issues); the following would not
174have compiled ::
175
176 zoo.insert( "bobo", // this is bad, but you get compile error
177 new monkey("bobo") );
178
179If a multimap is not needed, we can use ``operator[]()``
180to avoid the clumsiness::
181
182 boost::ptr_map<std::string,animal> animals;
183 animals["bobo"].set_name("bobo");
184
185This requires a default constructor for animals and
186a function to do the initialization, in this case ``set_name()``.
187
188A better alternative is to use `Boost.Assign <../../assign/index.html>`_
189to 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
195For 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
206Null values
207-----------
208
209By default, if you try to insert null into a container, an exception
210is thrown. If you want to allow nulls, then you must
211say 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
219Once you have inserted a null into the container, you must
220always 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
229If 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
238Note that it is meaningless to insert
239null into ``ptr_set`` and ``ptr_multiset``.
240
241Cloneability
242------------
243
244In OO programming it is typical to prohibit copying of objects; the
245objects 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
252If the OO hierarchy thus allows cloning, we need to tell the
253pointer containers how cloning is to be done. This is simply
254done by defining a free-standing function, ``new_clone()``,
255in the same namespace as
256the object hierarchy::
257
258 inline animal* new_clone( const animal& a )
259 {
260 return a.clone();
261 }
262
263That is all, now a lot of functions in a pointer container
264can 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
271will 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
276The whole container can now also be cloned ::
277
278 zoo_type yet_another_zoo = zoo.clone();
279
280Copying or assigning the container has the same effect as cloning (though it is slightly cheaper)::
281
282 zoo_type yet_another_zoo = zoo;
283
284Copying 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
289This also works for maps::
290
291 boost::ptr_map<std::string,monkey> monkeys = ...;
292 boost::ptr_map<std::string,animal> animals = monkeys;
293
294New functions
295-------------
296
297Given that we know we are working with pointers, a few new functions
298make sense. For example, say you want to remove an
299animal 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
306You can think of ``auto_type`` as a non-copyable form of
307``std::auto_ptr``. Notice that when you release an object, the
308pointer is removed from the container and the containers size
309shrinks. 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
317You can also release the entire container if you
318want 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
329Let us assume we want to move an animal object from
330one zoo to another. In other words, we want to move the
331animal 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
337This kind of "move-semantics" is different from
338normal value-based containers. You can think of ``transfer()``
339as the same as ``splice()`` on ``std::list``.
340
341If 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
346A map is slightly different to iterate over than standard maps.
347Now 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
363Except for the check for null, this looks like it would with a normal map. But if ``age()`` had
364not been a ``const`` member function,
365it would not have compiled.
366
367Maps 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
381Every time there is a function that takes a ``T*`` parameter, there is
382also a function taking an ``std::auto_ptr<U>`` parameter. This is of course done
383to 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
388is complemented by ::
389
390 std::auto_ptr<Derived> p( new Derived );
391 vec.push_back( p );
392
393Notice that the template argument for ``std::auto_ptr`` does not need to
394follow the template argument for ``ptr_vector`` as long as ``Derived*``
395can be implicitly converted to ``Base*``.
396
397Algorithms
398----------
399
400Unfortunately it is not possible to use pointer containers with
401mutating algorithms from the standard library. However,
402the most useful ones
403are 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
411Notice that predicates are automatically wrapped in an `indirect_fun`_ object.
412
413.. _`indirect_fun`: indirect_fun.html
414
415You 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
420If you just want to remove certain elements, use ``erase_if``::
421
422 zoo.erase_if( my_predicate() );
423
424Finally 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
431That 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