4.4.1
Freundlich's C++ toolkit
Loading...
Searching...
No Matches
Classes | Functions
fcppt.smart_pointers

Description

unique_ptr, shared_ptr and weak_ptr without default constructors.

Introduction

A smart pointer is a class that takes ownership over a 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 all smart pointers that are also in C++11 with the following changes:

Smart pointer types

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

Class name

Description

fcppt::unique_ptr

A move-only smart pointer that is the unique owner of an object. This should be the default choice of smart pointer.

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.

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.

For most use cases, unique ptrs should be preferred over shared ptrs.

The general traits of a shared ptr are as follows:

Here is a simple example using shared pointers.

using int_ptr = fcppt::shared_ptr<int>;
// Objects of this class should share ownership of int_ptrs
class owner
{
public:
explicit owner(int_ptr _ptr) : ptr_{std::move(_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 const owner1{ptr};
// Copies from owner1 to owner2, increasing the shared count to 3
owner const owner2{// NOLINT(performance-unnecessary-copy-initialization)
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.

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) // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
{
//
}
// 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(1)
// b) throw_something()
// c) int_ptr(...) is never reached and we have a leak
take_pointer(int_ptr(new int(1)), 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>(1), 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.

A weak ptr can be used as follows:

using weak_int_ptr = fcppt::weak_ptr<int>;
using shared_int_ptr = fcppt::shared_ptr<int>;
weak_int_ptr weak_p{};
{
shared_int_ptr const int_ptr(fcppt::make_shared_ptr<int>(1));
// Create a weak_ptr to the shared_ptr
weak_p = weak_int_ptr{int_ptr};
if (weak_p.lock().has_value())
{
std::cout << "A shared ptr is still alive.\n";
}
}
// Observe if a shared_ptr is still alive. At this point, no
// shared_ptr is alive.
if (!weak_p.lock().has_value())
{
std::cout << "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
{
base() = default;
virtual ~base() = default;
};
struct derived : base
{
FCPPT_NONMOVABLE(derived);
derived() = default;
~derived() override = default;
};
void cast()
{
using base_ptr = fcppt::shared_ptr<base>;
base_ptr const ptr{new derived()};
using derived_ptr = fcppt::shared_ptr<derived>;
fcppt::optional::object<derived_ptr> const dptr{fcppt::dynamic_pointer_cast<derived>(ptr)};
if (dptr.has_value())
{
std::cout << "ptr points to a derived.\n";
}
}

Unique Pointers

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 as desired. The following example shows how such a factory can be created.

using unique_int_ptr = fcppt::unique_ptr<int>;
// 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>(1);
}

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

The factory can be used as follows:

// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
void int_ptr_arg(unique_int_ptr &&ptr) { std::cout << *ptr << '\n'; }
void test() { 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>(1));
// 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>(1));
// Implicit move is not allowed
/*
int_ptr_arg(ptr );
*/
// Make the move explicit
int_ptr_arg(std::move(ptr));
// ptr is now the null pointer
std::cout << ptr.get_pointer() // NOLINT(bugprone-use-after-move,hicpp-invalid-access-moved)
<< '\n';
}

Converting Unique Pointers

Unique pointers are not implicitly convertible to any other unique pointers. To convert a unique pointer to a unique pointer to base, use fcppt::unique_ptr_to_base.

struct base
{
base() = default;
virtual ~base() = default;
};
struct derived : base
{
FCPPT_NONMOVABLE(derived);
derived() = default;
~derived() override = default;
};
void test4()
{
using base_ptr = fcppt::unique_ptr<base>;
base_ptr const foo{fcppt::unique_ptr_to_base<base>(fcppt::make_unique_ptr<derived>())};
}

Similarly, fcppt::unique_ptr_to_const must be used to obtain a unique pointer to a const object.

using const_int_ptr = fcppt::unique_ptr<int const>;
const_int_ptr const foo{fcppt::unique_ptr_to_const(fcppt::make_unique_ptr<int>(1))};

Const Unique Pointers

fcppt used to provide a scoped_ptr class similar to boost::scoped_ptr that additionally took a deleter. This class has been removed in favor of const unique ptrs.

using scoped_int_ptr = fcppt::unique_ptr<int const>;
scoped_int_ptr const ptr(fcppt::make_unique_ptr<int const>(1));

A unique ptr that has been declared const cannot be copied nor moved. Additionally, it can also not be swapped.

Unique Pointers and Pimpl

A unique ptr can also be used to implement the pimpl idiom. When a unique ptr object is defined, the pointed to object doesn't need to be complete. It only has to be complete when the destructor of the unique ptr is instantiated. Therefore, an implementation can be hidden by using unique ptrs as shown in the following example:

class foo_impl;
class foo
{
// Explicitly disable copying and moving
public:
foo();
~foo();
private:
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
};

Because foo has an explicitly declared destructor, the destruction of the implementation can be hidden in a source file.

class foo_impl
{
// Something here
};
foo::foo() : impl_(fcppt::make_unique_ptr<foo_impl>()) {}
foo::~foo() = default;

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::default_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_c_ptr const ptr{
// NOLINTNEXTLINE(cppcoreguidelines-no-malloc,hicpp-no-malloc)
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.
default_deleter.hpp Contains fcppt::default_deleter.
dynamic_pointer_cast.hpp Contains fcppt::dynamic_pointer_cast.
make_shared_ptr.hpp Contains fcppt::make_shared_ptr.
make_unique_ptr.hpp Contains fcppt::make_unique_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 The same as shared_ptr_impl.hpp
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 The same as unique_ptr_impl.hpp
unique_ptr_to_base.hpp Contains fcppt::unique_ptr_to_base.
unique_ptr_to_const.hpp Contains fcppt::unique_ptr_to_const.
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 The same as weak_ptr_impl.hpp

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::default_deleter
 A deleter that uses delete to destroy an object. More...
 
class  fcppt::enable_shared_from_this< Type >
 Allows an object to obtain a shared ptr to itself. More...
 
struct  fcppt::is_unique_ptr< Type >
 Tests if a type is an fcppt::unique_ptr. More...
 
class  fcppt::shared_ptr< Type, Deleter >
 A shared pointer class that gets the deleter as a template parameter. More...
 
struct  fcppt::shared_ptr_hash< fcppt::shared_ptr< Type > >
 A hash for fcppt::shared_ptr that hashes pointers. More...
 
class  fcppt::unique_ptr< Type, Deleter >
 A simpler unique_ptr that shouldn't be used as a null pointer. 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 >
fcppt::shared_ptr< Dest > fcppt::const_pointer_cast (fcppt::shared_ptr< Source const > const &_ptr)
 Casts an fcppt::shared_ptr using const_cast
 
template<typename Dest , typename Source >
fcppt::optional::object< fcppt::shared_ptr< Dest > > fcppt::dynamic_pointer_cast (fcppt::shared_ptr< Source > const &_ptr)
 Casts an fcppt::shared_ptr using dynamic_cast
 
template<typename Res , typename... Args>
fcppt::shared_ptr< Res > fcppt::make_shared_ptr (Args &&..._args)
 Like std::make_shared but for fcppt::shared_ptr.
 
template<typename Res , typename... Args>
fcppt::unique_ptr< Res > fcppt::make_unique_ptr (Args &&..._args)
 Like std::make_unique for fcppt::unique_ptr.
 
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) noexcept
 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 >
fcppt::shared_ptr< Dest > fcppt::static_pointer_cast (fcppt::shared_ptr< Source > const &_ptr)
 Casts an fcppt::shared_ptr using static_cast
 
template<typename Cast , typename Derived , typename Base , typename Deleter >
fcppt::variant::object< fcppt::unique_ptr< Derived, Deleter >, fcppt::unique_ptr< Base, Deleter > > fcppt::unique_ptr_dynamic_cast (fcppt::unique_ptr< Base, Deleter > &&_other) noexcept
 Casts a unique_ptr to a derived class.
 
template<typename Type >
fcppt::optional::object< fcppt::unique_ptr< Type > > fcppt::unique_ptr_from_std (std::unique_ptr< Type > &&_ptr)
 Converts a std::unique_ptr to an fcppt unique ptr.
 
template<typename Base , typename Derived , typename Deleter >
fcppt::unique_ptr< Base, Deleter > fcppt::unique_ptr_to_base (fcppt::unique_ptr< Derived, Deleter > &&_other) noexcept
 Casts a unique_ptr to a base class.
 
template<typename Type , typename Deleter >
fcppt::unique_ptr< Type const, Deleter > fcppt::unique_ptr_to_const (fcppt::unique_ptr< Type, Deleter > &&_other) noexcept
 Casts a unique_ptr to a const unique_ptr.
 
template<typename Type1 , typename Type2 , typename Deleter >
bool fcppt::operator< (fcppt::weak_ptr< Type1, Deleter > const &left, fcppt::weak_ptr< Type2, Deleter > const &right) noexcept
 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) noexcept
 Swaps two weak pointers.
 

Function Documentation

◆ const_pointer_cast()

template<typename Dest , typename Source >
fcppt::shared_ptr< Dest > fcppt::const_pointer_cast ( fcppt::shared_ptr< Source const > 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

◆ dynamic_pointer_cast()

template<typename Dest , typename Source >
fcppt::optional::object< fcppt::shared_ptr< Dest > > fcppt::dynamic_pointer_cast ( fcppt::shared_ptr< Source > 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 must 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

◆ make_shared_ptr()

template<typename Res , typename... Args>
fcppt::shared_ptr< Res > fcppt::make_shared_ptr ( Args &&...  _args)
inline

Like std::make_shared but for fcppt::shared_ptr.

◆ make_unique_ptr()

template<typename Res , typename... Args>
fcppt::unique_ptr< Res > fcppt::make_unique_ptr ( Args &&...  _args)
inline

Like std::make_unique for fcppt::unique_ptr.

◆ operator!=()

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

◆ operator<() [1/2]

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

◆ operator<() [2/2]

template<typename Type1 , typename Type2 , typename Deleter >
bool fcppt::operator< ( fcppt::weak_ptr< Type1, Deleter > const &  left,
fcppt::weak_ptr< Type2, Deleter > const &  right 
)
noexcept

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

◆ operator<<()

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 
)
inline

Outputs a shared pointer.

Outputs _ptr to _stream.

Returns
stream

◆ operator==()

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

◆ static_pointer_cast()

template<typename Dest , typename Source >
fcppt::shared_ptr< Dest > fcppt::static_pointer_cast ( fcppt::shared_ptr< Source > 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.

◆ swap() [1/2]

template<typename Type , typename Deleter >
void fcppt::swap ( fcppt::shared_ptr< Type, Deleter > &  left,
fcppt::shared_ptr< Type, Deleter > &  right 
)
noexcept

Swaps two shared pointers.

Swaps left and right

Parameters
leftThe left argument
rightThe right argument

◆ swap() [2/2]

template<typename Type , typename Deleter >
void fcppt::swap ( fcppt::weak_ptr< Type, Deleter > &  left,
fcppt::weak_ptr< Type, Deleter > &  right 
)
noexcept

Swaps two weak pointers.

Swaps left and right

Parameters
leftThe left argument
rightThe right argument

◆ unique_ptr_dynamic_cast()

template<typename Cast , typename Derived , typename Base , typename Deleter >
fcppt::variant::object< fcppt::unique_ptr< Derived, Deleter >, fcppt::unique_ptr< Base, Deleter > > fcppt::unique_ptr_dynamic_cast ( fcppt::unique_ptr< Base, Deleter > &&  _other)
inlinenoexcept

Casts a unique_ptr to a derived class.

Tries to cast the given unique ptr to Derived using the cast function Cast. The result is either a unique_ptr of type Derived, or (if the cast fails) of type Base.

Template Parameters
CastA cast function from fcppt.casts

◆ unique_ptr_from_std()

template<typename Type >
fcppt::optional::object< fcppt::unique_ptr< Type > > fcppt::unique_ptr_from_std ( std::unique_ptr< Type > &&  _ptr)

Converts a std::unique_ptr to an fcppt unique ptr.

◆ unique_ptr_to_base()

template<typename Base , typename Derived , typename Deleter >
fcppt::unique_ptr< Base, Deleter > fcppt::unique_ptr_to_base ( fcppt::unique_ptr< Derived, Deleter > &&  _other)
inlinenoexcept

Casts a unique_ptr to a base class.

◆ unique_ptr_to_const()

template<typename Type , typename Deleter >
fcppt::unique_ptr< Type const, Deleter > fcppt::unique_ptr_to_const ( fcppt::unique_ptr< Type, Deleter > &&  _other)
inlinenoexcept

Casts a unique_ptr to a const unique_ptr.