0.12.0
Freundlich's C++ toolkit
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Classes | Functions
fcppt.smart_pointers
fcppt

Description

Smart pointers and their utilities.

Introduction

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.

Smart pointer types

fcppt provides four smart pointer classes, each with their own trade-offs.

Class name Description

fcppt::shared_ptr

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.

fcppt::weak_ptr

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.

fcppt::unique_ptr

A replacement for std::auto_ptr. Only one unique ptr will manage the ownership at a time. It can be transfered into a shared ptr or into a scoped ptr. The difference to std::auto_ptr is that transferring ownership from one unique ptr to another is safer.

fcppt::scoped_ptr

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.

Shared Pointers

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:

Here is a simple example using shared pointers.

// Typedef a shared_ptr to in int
int
> int_ptr;
// Objects of this class should share ownership of int_ptrs
class owner
{
public:
explicit
owner(
int_ptr _ptr
)
:
ptr_(
_ptr
)
{
}
private:
int_ptr ptr_;
};
void
shared_ptr_example()
{
// Creates a shared_ptr
int_ptr const ptr(
new int(42)
);
// Copies the ownership to owner1, increasing the shared count to 2
owner owner1(
ptr
);
// Copies from owner1 to owner2, increasing the shared count to 3
owner owner2(
owner1
);
// The destruction of owner2, owner1 and ptr will free the int
}
}

Using make_shared

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.

Note
fcppt::make_shared_ptr takes every argument by value, which means that you have to use fcppt::ref or fcppt::cref for references.

Here is an example of how not using fcppt::make_shared_ptr can lead to a memory leak.

// Create a function that takes ownership of an int_ptr, but also takes another
// argument.
void
take_pointer(
int_ptr,
bool
)
{
//
}
// This function will be used to provide a bool value for take_pointer, but it
// throws when executed.
bool
throw_something()
{
throw std::runtime_error("test");
}
void
wrong()
{
// The order in which function arguments and their sub expressions are
// evaluated is unspecified. So it might be possible that they are
// evaluated as follows:
// a) new int(100)
// b) throw_something()
// c) int_ptr(...) is never reached and we have a leak
take_pointer(
int_ptr(
new int (100)
),
throw_something()
);
}

Using fcppt::make_shared_ptr eliminates this problem and also makes the dynamic memory management of the shared ptrs more efficient.

void
right()
{
take_pointer(
fcppt::make_shared_ptr<
int
>(
100
),
throw_something()
);
}

Weak Pointers

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:

typedef fcppt::weak_ptr<
int
> weak_int_ptr;
int
> shared_int_ptr;
shared_int_ptr int_ptr(
new int(42)
);
// Create a weak_ptr to the shared_ptr
weak_int_ptr weak_p(
int_ptr
);
{
// Observe if a shared_ptr is still alive, which it is
shared_int_ptr ref(
weak_p.lock()
);
if(
)
<< FCPPT_TEXT("A shared ptr is still alive.\n");
}
// Delete the shared_ptr
int_ptr.reset();
{
// Observe if a shared_ptr is still alive. At this point, no
// shared_ptr is alive.
shared_int_ptr ref(
weak_p.lock()
);
if(
!ref
)
<< FCPPT_TEXT("No shared ptrs are alive.\n");
}

Casting Shared Pointers

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:

struct base
{
virtual ~base()
{
}
};
struct derived
:
base
{};
void
cast()
{
base
> base_ptr;
base_ptr ptr(
new derived()
);
derived
> derived_ptr;
derived_ptr dptr(
derived
>(
ptr
)
);
if(
dptr
)
<< FCPPT_TEXT("ptr points to a derived.\n");
}

Unique Pointers

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:

Using Unique Pointers

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.

int
> unique_int_ptr;
// Create a unique_ptr factory
unique_int_ptr
int_ptr_factory()
{
// make_unique_ptr is a factory function to make a unique_ptr
// An rvalue is returned here, so no moving is necessary.
return
fcppt::make_unique_ptr<
int
>(
42
);
}

The return of make_unique_ptr doesn't require a move, because it returns an rvalue.

The factory can be used as follows:

void
int_ptr_arg(
unique_int_ptr ptr
)
{
<< *ptr
<< FCPPT_TEXT('\n');
}
void
test()
{
// moving unique_ptrs from rvalues works out of the box
int_ptr_arg(
int_ptr_factory()
);
}

Again, there is no move required because the factory also returns an rvalue.

Moving Unique Pointers

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.

unique_int_ptr
test2()
{
// ptr is a named object
unique_int_ptr ptr(
fcppt::make_unique_ptr<
int
>(
42
)
);
// ptr must be moved here to take ownership away from it
return
ptr
);
}

Consider the following example where an implicit move would be very dangerous:

void
test3()
{
unique_int_ptr ptr(
fcppt::make_unique_ptr<
int
>(
42
)
);
// Implicit move is not allowed
/*
int_ptr_arg(
ptr
);
*/
// Make the move explicit
int_ptr_arg(
ptr
)
);
// ptr is now the null pointer
<< ptr.get()
<< FCPPT_TEXT('\n');
}

Unique Pointer Limitations

There are some limitations for unique ptrs because they are only a hack in C++03:

Scoped Pointers

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:

int
> int_unique_ptr;
// A factory returning an int_unique_ptr
int_unique_ptr
factory();

A scoped ptr can then be used to hold onto a unique ptr.

void
receive_int_ptr()
{
int
> int_scoped_ptr;
// Take the int_unique_ptr and store it in a scoped_ptr
int_scoped_ptr const result(
factory()
);
<< *result
<< FCPPT_TEXT('\n');
}

Using Scoped Pointers for pimpl

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.

// Only declare my_class
class my_class;
// holder owns a my_class object using a scoped_ptr. At this class definition,
// my_class doesn't have to be defined. However, you have to make sure that
// holder is not copyable, and that its constructor and destructor are not
// inline, because they would require my_class to be defined.
class holder
{
holder
);
public:
holder();
~holder();
private:
my_class
> pimpl_;
};

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.

class my_class
{
// Imaginge a huge class with a lot of stuff in it that should rather
// not be included everywhere.
};
// Construct the scoped ptr pimpl_ using make_unique_ptr and take advantage of
// the fact that a scoped ptr can take ownership from a unique ptr.
holder::holder()
:
pimpl_(
fcppt::make_unique_ptr<
my_class
>()
)
{
}
holder::~holder()
{
}

Custom Deleters

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's Deleters

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();

Deleter example

The following example shows how fcppt::c_deleter can be used to free memory allocated via std::malloc

void,
> void_c_ptr;
void_c_ptr ptr(
std::malloc(
100
)
);

Header files

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.
 

Function Documentation

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

Casts the pointer stored in _ptr to type U * using const_cast.

Template Parameters
DestThe type of the destination shared_ptr
SourceThe type of the source shared_ptr
Parameters
_ptrThe source shared_ptr
Returns
The converted shared_ptr
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

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.

Template Parameters
DestThe type of the destination shared_ptr
SourceThe type of the source shared_ptr
Parameters
_ptrThe source shared_ptr
Returns
The converted shared_ptr or an empty shared_ptr if the dynamic_cast fails
template<typename Type1 , typename Type2 , typename Deleter >
bool fcppt::operator!= ( fcppt::unique_ptr< Type1, Deleter > const &  left,
fcppt::unique_ptr< Type2, Deleter > const &  right 
)
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.

Parameters
leftThe left argument
rightThe right argument
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.

Compares left and right for inequality, comparing their pointers. Pointers to Type1 and to Type2 must be inequality comparable.

Parameters
leftThe left argument
rightThe right argument
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.

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.

Parameters
leftThe left argument
rightThe right argument
template<typename Type1 , typename Type2 , typename Deleter >
bool fcppt::operator< ( fcppt::unique_ptr< Type1, Deleter > const &  left,
fcppt::unique_ptr< Type2, Deleter > const &  right 
)
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.

Parameters
leftThe left argument
rightThe right argument
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.

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.

Parameters
leftThe left argument
rightThe right argument
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.

Outputs ptr to stream.

Parameters
streamThe stream to write to
ptrThe shared pointer to output
Returns
stream
template<typename Type1 , typename Type2 , typename Deleter >
bool fcppt::operator== ( fcppt::unique_ptr< Type1, Deleter > const &  left,
fcppt::unique_ptr< Type2, Deleter > const &  right 
)
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.

Parameters
leftThe left argument
rightThe right argument
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.

Compares left and right for equality, comparing their pointers. Pointers to Type1 and to Type2 must be equality comparable.

Parameters
leftThe left argument
rightThe right argument
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

Casts the pointer stored in _ptr to type U * using static_cast.

Template Parameters
DestThe type of the destination shared_ptr
SourceThe type of the source shared_ptr
Parameters
_ptrThe source shared_ptr
Returns
The converted shared_ptr
Warning
The behaviour is undefined if the static_cast is not well formed.
template<typename Type , typename Deleter >
void fcppt::swap ( fcppt::weak_ptr< Type, Deleter > &  left,
fcppt::weak_ptr< Type, Deleter > &  right 
)

Swaps two weak pointers.

Swaps left and right

Parameters
leftThe left argument
rightThe right argument
template<typename Type , typename Deleter >
void fcppt::swap ( fcppt::scoped_ptr< Type, Deleter > &  left,
fcppt::scoped_ptr< Type, Deleter > &  right 
)

Swaps two scoped pointers.

Swaps left and right

Parameters
leftThe left argument
rightThe right argument
template<typename Type , typename Deleter >
void fcppt::swap ( fcppt::unique_ptr< Type, Deleter > &  left,
fcppt::unique_ptr< Type, Deleter > &  right 
)
inline

Swaps two unique pointers.

Swaps left and right

Parameters
leftThe left argument
rightThe right argument
template<typename Type , typename Deleter >
void fcppt::swap ( fcppt::shared_ptr< Type, Deleter > &  left,
fcppt::shared_ptr< Type, Deleter > &  right 
)

Swaps two shared pointers.

Swaps left and right

Parameters
leftThe left argument
rightThe right argument