|
0.12.0
|
|
Freundlich's C++ toolkit |
Smart pointers and their utilities.
C++ manages dynamic memory by raw pointers that you have to free explicitly at some point. The general problem with this approach is that it can be easily forgotten to free the memory. The reasons for that are that the programmer can simply forget or that a control flow is executed (for example, an exception is thrown), so that the point where the memory should be freed won't be reached.
A smart pointer is a class that takes ownership over the pointer, freeing the object pointed to when the smart pointer is destroyed. Such a smart pointer resides on the stack, so freeing is done automatically.
fcppt provides several kinds of smart pointers, where some of them are also provided by Boost. The difference is that the deleter (which dictates how the object is to be freed) is a template parameter for all classes. This is a trade-off and removes some of the dynamic behaviour, switching it for a statically type-safe one.
fcppt provides four smart pointer classes, each with their own trade-offs.
| Class name | Description |
|---|---|
Manages objects using a shared count. Every shared ptr pointing to the same object increases the shared count by one. The object will only be destroyed when all shared ptrs have been destroyed. | |
A weak reference to an object managed by shared ptrs. This smart pointer doesn't contribute to the shared count and can be used to observe if shared ptrs are still alive. | |
A replacement for | |
A noncopyable smart pointer, similar to unique ptr. Only one scoped ptr will manage the ownership at a time. It can be transfered into a unique ptr or from a unique ptr. |
Multiple fcppt::shared_ptr that point to the same object share ownership by internally managing a shared count that counts how many shared ptrs are left. This shared count will be increased whenever a shared ptr is copied and decreased when one is destroyed.
Generally, it is advisable to think twice before using a shared ptr. Under most circumstances, shared ownership is not really necessary and a scoped ptr or a unique ptr should be used instead.
The general traits of a shared ptr are as follows:
Copying, destroying and assigning of shared ptrs is thread safe. This usually means that these operators have to consist of some atomic operations, making them a lot less cheap than they might seem.
Although the shared ptr gets its deleter as a template parameter, it does type erasure on it. This implies that the owned object does not have to be complete unless the shared ptr is constructed or dereferenced.
Because not only the shared count but also the owned object must be dynamically allocated, it is possible to put them both into the same memory block if the deleter is the default one that uses delete. This is done by fcppt::make_shared_ptr.
An fcppt::weak_ptr can be used to keep track of the shared ptrs to one object without contributing to the shared count. This way it is possible to observe if shared ptrs are still alive.
Casting shared pointers must be done through special functions, so that the shared count between them is preserved.
Here is a simple example using shared pointers.
fcppt::make_shared_ptr can be used to place an object allocated via new into the same memory block as the shared count managed by the shared ptrs. Another reason to use this function is to avoid memory leaks, that can happen due to C++'s unspecified order of evaluation, if you are not careful.
Here is an example of how not using fcppt::make_shared_ptr can lead to a memory leak.
Using fcppt::make_shared_ptr eliminates this problem and also makes the dynamic memory management of the shared ptrs more efficient.
A weak pointer can be used to keep track of the shared ptrs to one object without contributing to the shared count. We can then observe if a shared ptr is still alive. This can also be used to break cycles, but it is not recommended to introduce cycles anyway.
A weak ptr can be used as follows:
When casting shared ptrs, using static_cast, dynamic_cast or const_cast directly will not work, because the shared count will not be preserved. Instead, we have to use one of the special functions fcppt::static_pointer_cast, fcppt::dynamic_pointer_cast or fcppt::const_pointer_cast.
Here is an example:
An fcppt::unique_ptr is a replacement for std::auto_ptr and is modeled after C++11's std::unique_ptr. In contrast to a shared ptr, a unique ptr always is the sole owner of an object.
The general traits of a unique ptr are as follows:
unique ptrs cannot be copied or assigned. Instead, they must be moved, which takes the ownership away from the original owner. Copying or assigning from rvalues works without moving.
unique ptrs don't use type erasure for their deleter. This means that when constructing, copying, assigning, destroying or dereferencing unique ptrs, the type of the pointed to object must usually be complete (this depends on the deleter used).
fcppt::make_unique_ptr should be used to construct unique ptrs. It is similar to fcppt::make_shared_ptr in the sense that it helps to avoid memory leaks, but it is not more efficient than normal construction of unique ptrs, because there is no shared count to keep track of.
The first thing to note is that unique ptrs are an excellent candidate for factory functions. They don't impose overly strict ownership requirements like shared ptr does. However, unique ptrs can be converted into shared ptrs or scoped ptrs as desired. The following example shows how such a factory can be created.
The return of make_unique_ptr doesn't require a move, because it returns an rvalue.
The factory can be used as follows:
Again, there is no move required because the factory also returns an rvalue.
The next example shows when a move is required. This is generally true when an lvalue is involved (which means a named object here). The reason for this is to ensure that a unique ptr doesn't accidentally get its object disowned.
Consider the following example where an implicit move would be very dangerous:
There are some limitations for unique ptrs because they are only a hack in C++03:
Non move aware code will not work with unique ptrs, especially function and bind.
Converting an fcppt::unique_ptr<Derived> into an fcppt::unique_ptr<Base> currently doesn't work implicitly. This must be done explicitly instead.
fcppt::scoped_ptr is similar to fcppt::unique_ptr, except it cannot even be moved and is completely noncopyable. Like for unique ptrs, no type erasure is done for the deleter.
Such a scoped ptr is usually a good choice if you want to hold onto something returned by a factory creating unique ptrs.
Such a factory can again be declared as follows:
A scoped ptr can then be used to hold onto a unique ptr.
pimpl is an idiom that allows the type of the pointed to object to be incomplete where the scoped ptr object is declared. As previously noted, a scoped ptr does require its type to be complete, but only when it is constructed or destroyed, not when an object is declared.
This can then be used to leave the pointed to object undefined in the header of a class.
The constructor and destructor of such a class can then be defined in a separate translation unit where the definition of the owned object's class is known.
As previously mentioned, fcppt's smart pointers all take the deleter as a template parameter in order to ensure maximum type safety. Such a deleter must have the following properties:
For some smart pointer over type Type the deleter must be callable with an expression of type Type *. The deleter must ensure to destroy the object if it is not a null pointer.
fcppt predefines several deleters:
For some invented variable name ptr of type Type * their semantics are as follows:
| fcppt::heap_deleter | delete ptr; |
| fcppt::c_deleter | std::free(ptr); |
| fcppt::com_deleter | if(ptr) ptr->Release(); |
The following example shows how fcppt::c_deleter can be used to free memory allocated via std::malloc
| Header file | Description |
|---|---|
c_deleter.hpp | Contains fcppt::c_deleter |
com_deleter.hpp | Contains fcppt::com_deleter |
const_pointer_cast.hpp | Contains fcppt::const_pointer_cast |
dynamic_pointer_cast.hpp | Contains fcppt::dynamic_pointer_cast |
heap_deleter.hpp | Contains fcppt::heap_deleter |
make_shared_ptr.hpp | Contains fcppt::make_shared_ptr |
make_unique_ptr.hpp | Contains fcppt::make_unique_ptr |
move.hpp | Contains fcppt::move |
scoped_ptr_fwd.hpp | Contains fcppt::scoped_ptr's declaration. |
scoped_ptr_decl.hpp | Contains fcppt::scoped_ptr's definition. |
scoped_ptr_impl.hpp | Contains the definition of fcppt::scoped_ptr's member functions. |
scoped_ptr.hpp | Contains all of fcppt::scoped_ptr |
shared_ptr_fwd.hpp | Contains fcppt::shared_ptr's declaration. |
shared_ptr_decl.hpp | Contains fcppt::shared_ptr's definition. |
shared_ptr_impl.hpp | Contains the definition of fcppt::shared_ptr's member functions. |
shared_ptr.hpp | Contains all of fcppt::shared_ptr, fcppt::make_shared_ptr, and the cast functions. |
static_pointer_cast.hpp | Contains fcppt::static_pointer_cast |
unique_ptr_fwd.hpp | Contains fcppt::unique_ptr's declaration. |
unique_ptr_decl.hpp | Contains fcppt::unique_ptr's definition. |
unique_ptr_impl.hpp | Contains the definition of fcppt::unique_ptr's member functions. |
unique_ptr.hpp | Contains all of fcppt::unique_ptr and fcppt::make_unique_ptr |
weak_ptr_fwd.hpp | Contains fcppt::weak_ptr's declaration. |
weak_ptr_decl.hpp | Contains fcppt::weak_ptr's definition. |
weak_ptr_impl.hpp | Contains the definition of fcppt::weak_ptr's member functions. |
weak_ptr.hpp | Contains all of fcppt::weak_ptr |
Classes | |
| struct | fcppt::c_deleter |
A deleter that uses std::free to destroy an object. More... | |
| struct | fcppt::com_deleter |
A deleter that uses the Release member function to destroy an object. More... | |
| struct | fcppt::heap_deleter |
A deleter that uses delete to destroy an object. More... | |
| class | fcppt::scoped_ptr< Type, Deleter > |
| A scoped pointer class that gets the deleter as a template parameter. More... | |
| class | fcppt::shared_ptr< Type, Deleter > |
| A shared pointer class that gets the deleter as a template parameter. More... | |
| class | fcppt::unique_ptr< Type, Deleter > |
A unique pointer class, designed to emulate C++11's std::unique_ptr More... | |
| class | fcppt::weak_ptr< Type, Deleter > |
| A weak reference to an object owned by a shared pointer. More... | |
Functions | |
| template<typename Dest , typename Source , typename Deleter > | |
| fcppt::shared_ptr< Dest, Deleter > const | fcppt::const_pointer_cast (fcppt::shared_ptr< Source const, Deleter > const &_ptr) |
Casts an fcppt::shared_ptr using const_cast | |
| template<typename Dest , typename Source , typename Deleter > | |
| fcppt::shared_ptr< Dest, Deleter > const | fcppt::dynamic_pointer_cast (fcppt::shared_ptr< Source, Deleter > const &_ptr) |
Casts an fcppt::shared_ptr using dynamic_cast | |
| template<typename Type , typename Deleter > | |
| void | fcppt::swap (fcppt::scoped_ptr< Type, Deleter > &left, fcppt::scoped_ptr< Type, Deleter > &right) |
| Swaps two scoped pointers. | |
| template<typename Type1 , typename Type2 , typename Deleter > | |
| bool | fcppt::operator== (fcppt::shared_ptr< Type1, Deleter > const &left, fcppt::shared_ptr< Type2, Deleter > const &right) |
| Compares two shared ptrs for equality. | |
| template<typename Type1 , typename Type2 , typename Deleter > | |
| bool | fcppt::operator!= (fcppt::shared_ptr< Type1, Deleter > const &left, fcppt::shared_ptr< Type2, Deleter > const &right) |
| Compares two shared ptrs for inequality. | |
| template<typename Type1 , typename Type2 , typename Deleter > | |
| bool | fcppt::operator< (fcppt::shared_ptr< Type1, Deleter > const &left, fcppt::shared_ptr< Type2, Deleter > const &right) |
| Checks if one shared ptr is less than the other. | |
| template<typename Type , typename Deleter > | |
| void | fcppt::swap (fcppt::shared_ptr< Type, Deleter > &left, fcppt::shared_ptr< Type, Deleter > &right) |
| Swaps two shared pointers. | |
| template<typename Ch , typename Traits , typename Type , typename Deleter > | |
| std::basic_ostream< Ch, Traits > & | fcppt::operator<< (std::basic_ostream< Ch, Traits > &stream, fcppt::shared_ptr< Type, Deleter > const &ptr) |
| Outputs a shared pointer. | |
| template<typename Dest , typename Source , typename Deleter > | |
| fcppt::shared_ptr< Dest, Deleter > const | fcppt::static_pointer_cast (fcppt::shared_ptr< Source, Deleter > const &_ptr) |
Casts an fcppt::shared_ptr using static_cast | |
| template<typename Type , typename Deleter > | |
| void | fcppt::swap (fcppt::unique_ptr< Type, Deleter > &left, fcppt::unique_ptr< Type, Deleter > &right) |
| Swaps two unique pointers. | |
| template<typename Type1 , typename Type2 , typename Deleter > | |
| bool | fcppt::operator== (fcppt::unique_ptr< Type1, Deleter > const &left, fcppt::unique_ptr< Type2, Deleter > const &right) |
| Compares two unique ptrs for equality. | |
| template<typename Type1 , typename Type2 , typename Deleter > | |
| bool | fcppt::operator!= (fcppt::unique_ptr< Type1, Deleter > const &left, fcppt::unique_ptr< Type2, Deleter > const &right) |
| Compares two unique ptrs for inequality. | |
| template<typename Type1 , typename Type2 , typename Deleter > | |
| bool | fcppt::operator< (fcppt::unique_ptr< Type1, Deleter > const &left, fcppt::unique_ptr< Type2, Deleter > const &right) |
| Checks if one unique ptr is less than the other. | |
| template<typename Type1 , typename Type2 , typename Deleter > | |
| bool | fcppt::operator< (fcppt::weak_ptr< Type1, Deleter > const &left, fcppt::weak_ptr< Type2, Deleter > const &right) |
| Checks if one weak ptr is less than the other. | |
| template<typename Type , typename Deleter > | |
| void | fcppt::swap (fcppt::weak_ptr< Type, Deleter > &left, fcppt::weak_ptr< Type, Deleter > &right) |
| Swaps two weak pointers. | |
| fcppt::shared_ptr< Dest, Deleter> const fcppt::const_pointer_cast | ( | fcppt::shared_ptr< Source const, Deleter > const & | _ptr | ) |
Casts an fcppt::shared_ptr using const_cast
Casts the pointer stored in _ptr to type U * using const_cast.
| Dest | The type of the destination shared_ptr |
| Source | The type of the source shared_ptr |
| _ptr | The source shared_ptr |
| fcppt::shared_ptr< Dest, Deleter> const fcppt::dynamic_pointer_cast | ( | fcppt::shared_ptr< Source, Deleter > const & | _ptr | ) |
Casts an fcppt::shared_ptr using dynamic_cast
Casts the pointer stored in _ptr to type U * using dynamic_cast. This means that T * and U be members of the same class hierarchy. If the cast succeeds, the resulting shared_ptr will share ownership with the source.
| Dest | The type of the destination shared_ptr |
| Source | The type of the source shared_ptr |
| _ptr | The source shared_ptr |
dynamic_cast fails
|
inline |
Compares two unique ptrs for inequality.
Compares left and right for inequality, comparing their pointers. Pointers to Type1 and to Type2 must be inequality comparable.
| left | The left argument |
| right | The right argument |
| bool fcppt::operator!= | ( | fcppt::shared_ptr< Type1, Deleter > const & | left, |
| fcppt::shared_ptr< Type2, Deleter > const & | right | ||
| ) |
Compares two shared ptrs for inequality.
Compares left and right for inequality, comparing their pointers. Pointers to Type1 and to Type2 must be inequality comparable.
| left | The left argument |
| right | The right argument |
| bool fcppt::operator< | ( | fcppt::weak_ptr< Type1, Deleter > const & | left, |
| fcppt::weak_ptr< Type2, Deleter > const & | right | ||
| ) |
Checks if one weak ptr is less than the other.
Checks if left is less than right, comparing their pointers with std::less.
Pointers to Type1 and to Type2 must be comparable using std::less.
| left | The left argument |
| right | The right argument |
|
inline |
Checks if one unique ptr is less than the other.
Checks if left is less than right, comparing their pointers with std::less.
Pointers to Type1 and to Type2 must be comparable using std::less.
| left | The left argument |
| right | The right argument |
| bool fcppt::operator< | ( | fcppt::shared_ptr< Type1, Deleter > const & | left, |
| fcppt::shared_ptr< Type2, Deleter > const & | right | ||
| ) |
Checks if one shared ptr is less than the other.
Checks if left is less than right, comparing their pointers with std::less.
Pointers to Type1 and to Type2 must be comparable using std::less.
| left | The left argument |
| right | The right argument |
| std::basic_ostream< Ch, Traits > & fcppt::operator<< | ( | std::basic_ostream< Ch, Traits > & | stream, |
| fcppt::shared_ptr< Type, Deleter > const & | ptr | ||
| ) |
Outputs a shared pointer.
Outputs ptr to stream.
| stream | The stream to write to |
| ptr | The shared pointer to output |
|
inline |
Compares two unique ptrs for equality.
Compares left and right for equality, comparing their pointers. Pointers to Type1 and to Type2 must be equality comparable.
| left | The left argument |
| right | The right argument |
| bool fcppt::operator== | ( | fcppt::shared_ptr< Type1, Deleter > const & | left, |
| fcppt::shared_ptr< Type2, Deleter > const & | right | ||
| ) |
Compares two shared ptrs for equality.
Compares left and right for equality, comparing their pointers. Pointers to Type1 and to Type2 must be equality comparable.
| left | The left argument |
| right | The right argument |
| fcppt::shared_ptr< Dest, Deleter> const fcppt::static_pointer_cast | ( | fcppt::shared_ptr< Source, Deleter > const & | _ptr | ) |
Casts an fcppt::shared_ptr using static_cast
Casts the pointer stored in _ptr to type U * using static_cast.
| Dest | The type of the destination shared_ptr |
| Source | The type of the source shared_ptr |
| _ptr | The source shared_ptr |
static_cast is not well formed. | void fcppt::swap | ( | fcppt::weak_ptr< Type, Deleter > & | left, |
| fcppt::weak_ptr< Type, Deleter > & | right | ||
| ) |
Swaps two weak pointers.
Swaps left and right
| left | The left argument |
| right | The right argument |
| void fcppt::swap | ( | fcppt::scoped_ptr< Type, Deleter > & | left, |
| fcppt::scoped_ptr< Type, Deleter > & | right | ||
| ) |
Swaps two scoped pointers.
Swaps left and right
| left | The left argument |
| right | The right argument |
|
inline |
Swaps two unique pointers.
Swaps left and right
| left | The left argument |
| right | The right argument |
| void fcppt::swap | ( | fcppt::shared_ptr< Type, Deleter > & | left, |
| fcppt::shared_ptr< Type, Deleter > & | right | ||
| ) |
Swaps two shared pointers.
Swaps left and right
| left | The left argument |
| right | The right argument |
1.8.2