scoped_array
Header:
"boost/scoped_array.hpp"
The need for dynamically allocated arrays is usually best handled by std::
vector, but there are two cases when it makes good sense to use arrays: for
optimization, as there is some overhead in size and speed for vector; and for
expression of intent, making it clear that bounds are fixed.
[5]
Dynamically allocated
arrays are exposed to the same dangers as ordinary pointers, with the added (and
all too common) mistake of invoking the delete operator instead of the
delete[] operator. I've seen that mistake in places one could hardly imagine,
such as in widely used, proprietary container classes! scoped_array does for
arrays what scoped_ptr does for pointers to single objects: It deletes the
memory. The difference is that scoped_array does it using the delete[]
operator.
[5]
These are not clear-cut advantages. Indeed, it is usually best to use
std::vector until performance measurements suggest the benefits of
scoped_array are warranted.
The reason that scoped_array is a separate class rather than being a
specialization of scoped_ptr
is because it is not possible to distinguish between
pointers to single objects and pointers to arrays using metaprogramming
techniques. Despite efforts to make that distinction, no one has found a reliable
way to do that because arrays decay so easily into pointers that carry no type
information indicating that they point to arrays. As a result, the onus is on you to
Reference-counted smart pointers assume ownership of the memory associated
with their stored pointers. The problem with sharing objects without the help of
smart pointers is that someone must, eventually, delete the shared memory. Who,
and when? Without reference-counted smart pointers, one must impose lifetime
management externally to the memory being managed, which typically means
stronger dependencies among the collective owners. That, in turn, impedes
reusability and adds complexity.
The class to be managed may have properties that make it a good candidate for use
with a reference-counted smart pointer. For example, the fact that it is expensive to
copy, or that part of its representation needs to be shared between instances, make
shared ownership desirable. There are also situations in which there is no explicit
owner of a shared resource. Using reference-counted smart pointers makes possible
sharing ownership among the objects that need access to the shared resource.
Reference-counted smart pointers also make it possible to store pointers to objects
in Standard Library containers without risk of leaks, especially in the face of
exceptions or when removing elements from the containers. When you store
pointers in containers, you can take advantage of polymorphism, improved
efficiency (if copying is expensive), and the ability to store the same objects in
multiple, associated containers for specialized lookups.
After you've determined that the use of a reference-counted smart pointer is
warranted, how do you choose whether to use an intrusive or non-intrusive design?
Non-intrusive smart pointers are almost always the better choice on account of
their general applicability, lack of impact on existing code, and flexibility. You can
use non-intrusive, reference-counted smart pointers with classes that you cannot or
don't wish to change. The usual way to adapt a class to work with an intrusive,
reference-counted smart pointer is to derive from a reference-counted base class.
That change may be more expensive than appears at first glance. At the very least,
it adds dependencies and decreases reusability.
[6]
It also typically increases object
shared_ptr(const weak_ptr<Y>& r);
template <class Y> explicit shared_ptr(std::auto_ptr<Y>& r);
shared_ptr& operator=(const shared_ptr& r);
void reset();
T& operator*() const;
T* operator->() const;
T* get() const;
bool unique() const;
long use_count() const;
operator unspecified-bool-type() const;
void swap(shared_ptr<T>& b);
};
template <class T,class U>
shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r);
}
Members
template <class Y> explicit shared_ptr(Y* p);
This constructor takes ownership of the supplied pointer p. The argument p must
be a valid pointer to Y. The reference count is set to 1 after construction. The only
exception that may be thrown from the constructor is std::bad_alloc (which
can only happen in the unlikely event that the reference counter cannot be allocated
from the free store).
template <class Y,class D> shared_ptr(Y* p,D d);
This constructor takes two arguments. The first is the resource that the
shared_ptr should take ownership of, and the second is an object that is
responsible for releasing that resource when the shared_ptr is destroyed. The
stored resource is passed to the object as d(p). Thus, valid values of p depend
upon d. If the reference counter cannot be allocated, shared_ptr tHRows an
exception of type std::bad_alloc.