Quick Links: |
Provide a wrapper that asserts a noexcept move constructor. More...
bslalg::NothrowMovableWrapper | wrapper class with noexcept move constructor |
bslalg::NothrowMovableWrapper<TYPE>
holding an object of TYPE
and providing no other functionality other than returning the wrapped object. The use of this class communicates to specific clients (see bslstl_function
) that the wrapped object should be treated as-if it has a noexcept
move constructor, even in C++03, where noexcept
does not exist. The client might, for example, move the object using efficient, non-exception-safe logic rather than, e.g., copying the object or storing it in heap memory so that its pointer can be moved. The behavior is undefined if the move constructor is invoked and does throw; typically resulting in terminate
being invoked. CountedType<TYPE>
, a wrapper around TYPE
that counts the number of extant CountedType
objects. We begin by defining the static count member along with the single value member: template <class TYPE> class CountedType { // CLASS DATA static int s_count; // DATA TYPE d_value;
CountedType
must provide the strong guarantee; i.e., if the move constructor of TYPE
throws an exception, then the moved-from CountedType
object must be left unchanged. To support this requirement, we next define a private static function, MoveIfNoexcept
, similar to the standard std::move_if_noexcept
, that returns a movable reference if its argument is no-throw move constructible and a const lvalue reference otherwise: // PRIVATE CLASS FUNCTIONS template <class TP> static typename bsl::conditional<bsl::is_nothrow_move_constructible<TP>::value, bslmf::MovableRef<TP>, const TP&>::type MoveIfNoexcept(TP& x);
public: // CLASS FUNCTIONS static int count() { return s_count; } // CREATORS CountedType(const TYPE& val); // Construct 'CountedType' from the specified 'val'. CountedType(const CountedType& original); // Copy construct '*this' from the specified 'original' object. CountedType(bslmf::MovableRef<CountedType> original); // Move construct '*this' from 'original'. If an exception is // thrown, by the constructor for 'TYPE' 'original' is unchanged. ~CountedType() { --s_count; } // Destroy this object. // MANIPULATORS TYPE& value() { return d_value; } // ACCESSORS const TYPE& value() const { return d_value; } };
MoveIfNoexcept
, which calls move
on its argument, allowing it to convert back to an lvalue if the return type is an lvalue reference: template <class TYPE> template <class TP> inline typename bsl::conditional<bsl::is_nothrow_move_constructible<TP>::value, bslmf::MovableRef<TP>, const TP&>::type CountedType<TYPE>::MoveIfNoexcept(TP& x) { return bslmf::MovableRefUtil::move(x); }
d_value
data members and increment the count: template <class TYPE> CountedType<TYPE>::CountedType(const TYPE& val) : d_value(val) { ++s_count; } template <class TYPE> CountedType<TYPE>::CountedType(const CountedType& original) : d_value(original.d_value) { ++s_count; }
original
into the d_value
member of *this
, but an exception thrown by TYPE
s move constructor would leave original
in a (valid but) unspecified state, violating the strong guarantee. Instead, we move the value only if we know that the move will succeed; otherwise, we copy it. This behavior is facilitated by the MoveIfNoexcept
function defined above: template <class TYPE> CountedType<TYPE>::CountedType(bslmf::MovableRef<CountedType> original) : d_value( MoveIfNoexcept(bslmf::MovableRefUtil::access(original).d_value)) { ++s_count; }
s_count
member to complete the class implementation: template <class TYPE> int CountedType<TYPE>::s_count = 0;
CountedType
class template, assume a simple client type, SomeType
that makes it easy to detect if it was move constructed. SomeType
holds an int
value that is set to -1 when it is moved from, as shown here: class SomeType { int d_value; public: SomeType(int v = 0) : d_value(v) { } // IMPLICIT SomeType(const SomeType& original) : d_value(original.d_value) { } SomeType(bslmf::MovableRef<SomeType> original) : d_value(bslmf::MovableRefUtil::access(original).d_value) { bslmf::MovableRefUtil::access(original).d_value = -1; } int value() const { return d_value; } };
SomeType
neglected to declare its move constructor as noexcept
. This might be an oversight or it could be an old class that predates both noexcept
and the bsl::is_nothrow_move_constructible
trait. It is even be possible that the move constructor might throw (though, of course, it doesn't in this simplified example). Regardless, the effect is that move-constructing a CountedType<SomeType>
will result in the move constructor actually performing a copy: void main() { CountedType<SomeType> obj1(1); CountedType<SomeType> obj2(bslmf::MovableRefUtil::move(obj1)); assert(1 == obj1.value().value()); // Copied, not moved from assert(1 == obj2.value().value());
SomeThing
will not throw on move, at least not in our application. In order to obtain the expected move optimization, we next wrap our 'SomeType in a bslalg::NothrowMovableWrapper
: CountedType<bslalg::NothrowMovableWrapper<SomeType> > obj3(SomeType(3)); CountedType<bslalg::NothrowMovableWrapper<SomeType> > obj4(bslmf::MovableRefUtil::move(obj3)); assert(-1 == obj3.value().unwrap().value()); // moved from assert(3 == obj4.value().unwrap().value()); }
#define Function_NothrowWrapper bsl_deprecated::NothrowMovableWrapper |
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper | ( | ) | [inline, inherited] |
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper | ( | bsl::allocator_arg_t | , | |
const allocator_type & | alloc | |||
) | [inline, inherited] |
Value-initialize the object wrapped by *this
. For allocator-aware TYPE
, optionally specify an alloc
(e.g., the address of a bslma::Allocator
object) to supply memory; otherwise, the default allocator is used.
References bsls::ObjectBuffer< TYPE >::address(), and bslma::ConstructionUtil::construct().
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper | ( | const TYPE & | val | ) | [inline, inherited] |
IMPLICIT:
References bsls::ObjectBuffer< TYPE >::address(), and bslma::ConstructionUtil::construct().
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper | ( | bsl::allocator_arg_t | , | |
const allocator_type & | alloc, | |||
const TYPE & | val | |||
) | [inline, inherited] |
Wrap the specified val
, using TYPE
s (possibly extended) copy constructor. For allocator-aware TYPE
, optionally specify an alloc
(e.g., the address of a bslma::Allocator
object) to supply memory; otherwise, the default allocator is used.
References bsls::ObjectBuffer< TYPE >::address(), and bslma::ConstructionUtil::construct().
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper | ( | bslmf::MovableRef< TYPE > | val | ) | [inline, inherited] |
IMPLICIT: Wrap the specified val
, using TYPE
s move constructor.
References bsls::ObjectBuffer< TYPE >::address(), bslma::ConstructionUtil::construct(), and bslmf::MovableRefUtil::move().
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper | ( | bsl::allocator_arg_t | , | |
const allocator_type & | alloc, | |||
bslmf::MovableRef< TYPE > | val | |||
) | [inline, inherited] |
Wrap the specified val
, using TYPE
s extended move constructor. Use the specified alloc
(e.g., the address of a bslma::Allocator
object) to supply memory. Note that this constructor will not be selected by overload resolution unless TYPE
is allocator aware.
References bsls::ObjectBuffer< TYPE >::address(), bslma::ConstructionUtil::construct(), and bslmf::MovableRefUtil::move().
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper | ( | const NothrowMovableWrapper< TYPE > & | original | ) | [inline, inherited] |
Copy construct from the specified original
wrapper using TYPE
s copy constructor.
References bsls::ObjectBuffer< TYPE >::address(), bslma::ConstructionUtil::construct(), and bslalg::NothrowMovableWrapper< TYPE >::unwrap().
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper | ( | bsl::allocator_arg_t | , | |
const allocator_type & | alloc, | |||
const NothrowMovableWrapper< TYPE > & | original | |||
) | [inline, inherited] |
Copy construct from the specified original
wrapper using TYPE
s extended copy constructor. Use the specified alloc
(e.g., the address of a bslma::Allocator
object) to supply memory. Note that this constructor will not be selected by overload resolution unless TYPE
is allocator aware.
References bsls::ObjectBuffer< TYPE >::address(), bslma::ConstructionUtil::construct(), and bslalg::NothrowMovableWrapper< TYPE >::unwrap().
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper | ( | bslmf::MovableRef< NothrowMovableWrapper< TYPE > > | original | ) | [inline, inherited] |
IMPLICIT: Move construct from the specified original
wrapper using TYPE
s move constructor. Note that this move constructor is unconditionally noexcept
, as that is the entire purpose of this wrapper.
References bslmf::MovableRefUtil::access(), bslma::ConstructionUtil::construct(), and bslmf::MovableRefUtil::move().
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper | ( | bsl::allocator_arg_t | , | |
const allocator_type & | alloc, | |||
bslmf::MovableRef< NothrowMovableWrapper< TYPE > > | original | |||
) | [inline, inherited] |
Move construct from the specified original
wrapper using TYPE
s extended move constructor. Use the specified alloc
(e.g., the address of a bslma::Allocator
object) to supply memory. Note that this constructor will not be selected by overload resolution unless TYPE
is allocator aware.
References bslmf::MovableRefUtil::access(), bsls::ObjectBuffer< TYPE >::address(), bslma::ConstructionUtil::construct(), bslmf::MovableRefUtil::move(), and bslalg::NothrowMovableWrapper< TYPE >::unwrap().
bslalg::NothrowMovableWrapper< TYPE >::~NothrowMovableWrapper | ( | ) | [inline, inherited] |
Destroy this object, invoking TYPE
s destructor.
References bsls::ObjectBuffer< TYPE >::object().
bslalg::NothrowMovableWrapper< TYPE >::ValueType & bslalg::NothrowMovableWrapper< TYPE >::unwrap | ( | ) | [inline, inherited] |
Return a reference offering modifiable access to the wrapped object.
References bsls::ObjectBuffer< TYPE >::object().
Referenced by bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper(), bslalg::NothrowMovableWrapper< TYPE >::operator ValueType &(), and bslalg::NothrowMovableWrapper< TYPE >::operator ValueType const &().
bslalg::NothrowMovableWrapper< TYPE >::allocator_type bslalg::NothrowMovableWrapper< TYPE >::get_allocator | ( | ) | const [inline, inherited] |
Return the allocator used to construct this object. Note that this method will fail to instantiate unless TYPE
is allocator-aware.
References bsls::ObjectBuffer< TYPE >::object().
bslalg::NothrowMovableWrapper< TYPE >::ValueType const & bslalg::NothrowMovableWrapper< TYPE >::unwrap | ( | ) | const [inline, inherited] |
Return a reference offering const access to the wrapped object.
References bsls::ObjectBuffer< TYPE >::object().