Pointer Container Library
| Author: | Thorsten Ottosen |
|---|---|
| Contact: | nesotto@cs.aau.dk or tottosen@dezide.com |
| Organizations: | Department of Computer Science, Aalborg University, and Dezide Aps |
| Date: | 27th of October 2007 |
| Copyright: | Thorsten Ottosen 2004-2007. Use, modification and distribution is subject to the Boost Software License, Version 1.0 (see LICENSE_1_0.txt). |
Overview
Boost.Pointer Container provides containers for holding heap-allocated objects in an exception-safe manner and with minimal overhead. The aim of the library is in particular to make OO programming easier in C++ by establishing a standard set of classes, methods and designs for dealing with OO specific problems
Motivation
Whenever a programmer wants to have a container of pointers to heap-allocated objects, there is usually only one exception-safe way: to make a container of smart pointers like boost::shared_ptr This approach is suboptimal if
- the stored objects are not shared, but owned exclusively, or
- the overhead implied by smart pointers is inappropriate
This library therefore provides standard-like containers that are for storing heap-allocated or cloned objects (or in case of a map, the mapped object must be a heap-allocated or cloned object). For each of the standard containers there is a pointer container equivalent that takes ownership of the objects in an exception safe manner. In this respect the library is intended to solve the so-called polymorphic class problem.
The advantages of pointer containers are
- Exception-safe pointer storage and manipulation.
- Notational convenience compared to the use of containers of pointers.
- Can be used for types that are neither Assignable nor Copy Constructible.
- The interface is slightly changed towards the domain of pointers instead of relying on the normal value-based interface. For example, now it is possible for pop_back() to return the removed element.
- Propagates constness such that one cannot modify the objects via a const_iterator.
- Built-in support for deep-copy semantics via the the Cloneable concept
The disadvantages are
- Less flexible than containers of smart pointers like boost::shared_ptr
When you do need shared semantics, this library is not what you need.
Upgrading from Boost v. 1.33.*
If you upgrade from one of these versions of Boost, then there has been one major interface change: map iterators now mimic iterators from std::map. Previously you may have written
for( boost::ptr_map<std::string,T>::iterator i = m.begin(), e = m.end();
i != e; ++i )
{
std::cout << "key:" << i.key();
std::cout << "value:" << *i;
i->foo(); // call T::foo()
}
and this now needs to be converted into
for( boost::ptr_map<std::string,T>::iterator i = m.begin(), e = m.end();
i != e; ++i )
{
std::cout << "key:" << i->first;
std::cout << "value:" << *i->second;
i->second->foo(); // call T::foo()
}
Apart from the above change, the library now also introduces
std::auto_ptr<T> overloads:
std::auto_ptr<T> p( new T ); container.push_back( p );
Derived-to-Base conversion in transfer():
boost::ptr_vector<Base> vec; boost::ptr_list<Derived> list; ... vec.transfer( vec.begin(), list ); // now ok
Also note that Boost.Assign introduces better support for pointer containers.
Upgrading from Boost v. 1.34.*
Serialization have now been made optional thanks to Sebastian Ramacher. You simply include <boost/ptr_container/serialize.hpp> or perhaps just one of the more specialized headers.
All containers are now copy-constructible and assignable. So you can e.g. now do:
boost::ptr_vector<Derived> derived = ...; boost::ptr_vector<Base> base( derived ); base = derived;
As the example shows, derived-to-base class conversions are also allowed.
A few general functions have been added:
VoidPtrContainer& base(); const VoidPtrContainer& base() const;
These allow direct access to the wrapped container which is somtimes needed when you want to provide extra functionality.
A few new functions have been added to sequences:
void resize( size_type size ); void resize( size_type size, T* to_clone );
ptr_vector<T> has a few new helper functions to integrate better with C-arrays:
void transfer( iterator before, T** from, size_type size, bool delete_from = true ); T** c_array();
Finally you can now also "copy" and "assign" an auto_type ptr by calling move():
boost::ptr_vector<T>::auto_type move_ptr = ...; return boost::ptr_container::move( move_ptr );
Future Developments
There are indications that the void* implementation has a slight performance overhead compared to a T* based implementation. Furthermore, a T* based implementation is so much easier to use type-safely with algorithms. Therefore I anticipate to move to a T* based implementation.
Acknowledgements
The following people have been very helpful:
- Bjørn D. Rasmussen for unintentionally motivating me to start this library
- Pavel Vozenilek for asking me to make the adapters
- David Abrahams for the indirect_fun design
- Pavol Droba for being review manager
- Ross Boylan for trying out a prototype for real
- Felipe Magno de Almeida for giving fedback based on using the library in production code even before the library was part of boost
- Jonathan Turkanis for supplying his move_ptr framework which is used internally
- Stefan Slapeta and Howard Hinnant for Metrowerks support
- Russell Hind for help with Borland compatibility
- Jonathan Wakely for his great help with GCC compatibility and bug fixes
- Pavel Chikulaev for comments and bug-fixes
- Andreas Hommel for fixing the nasty Metrowerks bug
- Charles Brockman for his many comments on the documentation
- Sebastian Ramacher for implementing the optinal serialization support
References
| [1] | Matt Austern: "The Standard Librarian: Containers of Pointers" , C/C++ Users Journal Experts Forum. |
| [2] | Bjarne Stroustrup, "The C++ Programming Language", Appendix E: "Standard-Library Exception Safety" |
| [3] | Herb Sutter, "Exceptional C++". |
| [4] | Herb Sutter, "More Exceptional C++". |
| [5] | Kevlin Henney: "From Mechanism to Method: The Safe Stacking of Cats" , C++ Experts Forum, February 2002. |
| [6] | Some of the few earlier attempts of pointer containers I have seen are the rather interesting NTL and the pointainer. As of this writing both libraries are not exceptions-safe and can leak. |
| [7] | INTERNATIONAL STANDARD, Programming languages --- C++, ISO/IEC 14882, 1998. See section 23 in particular. |
| [8] | C++ Standard Library Closed Issues List (Revision 27), Item 218, Algorithms do not use binary predicate objects for default comparisons. |
| [9] | C++ Standard Library Active Issues List (Revision 27), Item 226, User supplied specializations or overloads of namespace std function templates. |
| [10] | Harald Nowak, "A remove_if for vector", C/C++ Users Journal, July 2001. |
| [11] | (1, 2) Boost smart pointer timings |
| [12] | (1, 2) NTL: Array vs std::vector and boost::shared_ptr |
| [13] | Kevlin Henney, Null Object, 2002. |
| Copyright: | Thorsten Ottosen 2004-2006. |
|---|
