|
| | bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper () |
| |
| | bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper (bsl::allocator_arg_t, const allocator_type &alloc) |
| |
| | bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper (const TYPE &val) |
| |
| | bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper (bsl::allocator_arg_t, const allocator_type &alloc, const TYPE &val) |
| |
| | bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper (bslmf::MovableRef< TYPE > val) |
| | Wrap the specified val, using TYPEs move constructor.
|
| |
| | bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper (bsl::allocator_arg_t, const allocator_type &alloc, bslmf::MovableRef< TYPE > val) |
| |
| | bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper (const NothrowMovableWrapper &original) |
| |
| | bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper (bsl::allocator_arg_t, const allocator_type &alloc, const NothrowMovableWrapper &original) |
| |
| | bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper (bslmf::MovableRef< NothrowMovableWrapper > original) BSLS_KEYWORD_NOEXCEPT |
| |
| | bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper (bsl::allocator_arg_t, const allocator_type &alloc, bslmf::MovableRef< NothrowMovableWrapper > original) |
| |
| | bslalg::NothrowMovableWrapper< TYPE >::~NothrowMovableWrapper () |
| | Destroy this object, invoking TYPEs destructor.
|
| |
| ValueType & | bslalg::NothrowMovableWrapper< TYPE >::unwrap () |
| |
| allocator_type | bslalg::NothrowMovableWrapper< TYPE >::get_allocator () const |
| |
| ValueType const & | bslalg::NothrowMovableWrapper< TYPE >::unwrap () const |
| | Return a reference offering const access to the wrapped object.
|
| |
Outline
Purpose
Provide a wrapper that asserts a noexcept move constructor.
Classes
- See also
- bslalg_movablewrapperutil
Description
This component provides a wrapper class template 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.
Usage
Example 1
In this example, we define a class template, 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 {
static int s_count;
TYPE d_value;
Because of externally-imposed requirements, the move constructor for 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:
template <class TP>
static typename
MoveIfNoexcept(TP& x);
Definition bslmf_movableref.h:751
Definition bslmf_conditional.h:120
We next finish out the class definition with a constructor, copy constructor, move constructor, destructor, and member functions to retrieve the count and value:
public:
static int count() { return s_count; }
CountedType(const TYPE& val);
CountedType(const CountedType& original);
~CountedType() { --s_count; }
TYPE& value() { return d_value; }
const TYPE& value() const { return d_value; }
};
Next, we implement 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
CountedType<TYPE>::MoveIfNoexcept(TP& x)
{
}
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1060
Next, we implement the value constructor and copy constructor, which simply copy their argument into the 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;
}
We're now ready implement the move constructor. Logically, we would simply move the value from original into the d_value member of *this, but an exception thrown by TYPEs 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>
: d_value(
MoveIfNoexcept(
bslmf::MovableRefUtil::access(original).d_value))
{
++s_count;
}
Definition bdlbb_blob.h:576
Finally, we define the s_count member to complete the class implementation:
template <class TYPE>
int CountedType<TYPE>::s_count = 0;
To test the 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) { }
SomeType(const SomeType& original) : d_value(original.d_value) { }
: d_value(
bslmf::MovableRefUtil::access(original).d_value)
int value() const { return d_value; }
};
static t_TYPE & access(t_TYPE &ref) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1032
Notice that 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);
assert(1 == obj1.value().value());
assert(1 == obj2.value().value());
For the purpose of this example, we can be sure that 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> >
assert(-1 == obj3.value().unwrap().value());
assert(3 == obj4.value().unwrap().value());
}
◆ get_allocator()
Return the allocator used to construct this object. Note that this method will fail to instantiate unless TYPE is allocator-aware.
◆ NothrowMovableWrapper() [1/10]
◆ NothrowMovableWrapper() [2/10]
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.
◆ NothrowMovableWrapper() [3/10]
Move construct from the specified original wrapper using TYPEs 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.
◆ NothrowMovableWrapper() [4/10]
Wrap the specified val, using TYPEs 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.
◆ NothrowMovableWrapper() [5/10]
Copy construct from the specified original wrapper using TYPEs 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.
◆ NothrowMovableWrapper() [6/10]
◆ NothrowMovableWrapper() [7/10]
◆ NothrowMovableWrapper() [8/10]
◆ NothrowMovableWrapper() [9/10]
Copy construct from the specified original wrapper using TYPEs copy constructor.
◆ NothrowMovableWrapper() [10/10]
Wrap the specified val, using TYPEs (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.
◆ unwrap() [1/2]
Return a reference offering modifiable access to the wrapped object.
◆ unwrap() [2/2]
◆ ~NothrowMovableWrapper()