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.
- No memory-overhead as containers of smart pointers can have (see and ).
- Usually faster than using containers of smart pointers (see and ).
- 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 s.t. one cannot modify the objects via a const_iterator.
- Built-in support for deep-copy semantics via the The Clobable 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.
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.