BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslalg_nothrowmovablewrapper

Functions

 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.
 
ValueTypebslalg::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.
 

Detailed Description

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 {
// CLASS DATA
static int s_count;
// DATA
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:

// PRIVATE CLASS FUNCTIONS
template <class TP>
static typename
bslmf::MovableRef<TP>, const TP&>::type
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:
// CLASS FUNCTIONS
static int count() { return s_count; }
// CREATORS
/// Construct `CountedType` from the specified `val`.
CountedType(const TYPE& val);
// Copy construct `*this` from the specified `original` object.
CountedType(const CountedType& original);
// Move construct `*this` from `original`. If an exception is
// thrown, by the constructor for `TYPE` `original` is unchanged.
CountedType(bslmf::MovableRef<CountedType> original);
/// Destroy this object.
~CountedType() { --s_count; }
// MANIPULATORS
TYPE& value() { return d_value; }
// ACCESSORS
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
bslmf::MovableRef<TP>, const TP&>::type
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>
CountedType<TYPE>::CountedType(bslmf::MovableRef<CountedType> original)
: 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) { } // 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; }
};
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);
CountedType<SomeType> obj2(bslmf::MovableRefUtil::move(obj1));
assert(1 == obj1.value().value()); // Copied, not moved from
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()); // moved from
assert(3 == obj4.value().unwrap().value());
}

Function Documentation

◆ get_allocator()

template<class TYPE >
bslalg::NothrowMovableWrapper< TYPE >::allocator_type bslalg::NothrowMovableWrapper< TYPE >::get_allocator ( ) const
inline

Return the allocator used to construct this object. Note that this method will fail to instantiate unless TYPE is allocator-aware.

◆ NothrowMovableWrapper() [1/10]

template<class TYPE >
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper ( )
inline

◆ NothrowMovableWrapper() [2/10]

template<class TYPE >
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper ( bsl::allocator_arg_t  ,
const allocator_type alloc 
)
inline

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]

template<class TYPE >
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper ( bsl::allocator_arg_t  ,
const allocator_type alloc,
bslmf::MovableRef< NothrowMovableWrapper< TYPE > >  original 
)
inline

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]

template<class TYPE >
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper ( bsl::allocator_arg_t  ,
const allocator_type alloc,
bslmf::MovableRef< TYPE >  val 
)
inline

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]

template<class TYPE >
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper ( bsl::allocator_arg_t  ,
const allocator_type alloc,
const NothrowMovableWrapper< TYPE > &  original 
)
inline

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]

template<class TYPE >
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper ( bsl::allocator_arg_t  ,
const allocator_type alloc,
const TYPE &  val 
)
inline

◆ NothrowMovableWrapper() [7/10]

template<class TYPE >
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper ( bslmf::MovableRef< NothrowMovableWrapper< TYPE > >  original)
inline

◆ NothrowMovableWrapper() [8/10]

template<class TYPE >
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper ( bslmf::MovableRef< TYPE >  val)
inline

◆ NothrowMovableWrapper() [9/10]

template<class TYPE >
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper ( const NothrowMovableWrapper< TYPE > &  original)
inline

Copy construct from the specified original wrapper using TYPEs copy constructor.

◆ NothrowMovableWrapper() [10/10]

template<class TYPE >
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper ( const TYPE &  val)
inline

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]

template<class TYPE >
bslalg::NothrowMovableWrapper< TYPE >::ValueType & bslalg::NothrowMovableWrapper< TYPE >::unwrap ( )
inline

Return a reference offering modifiable access to the wrapped object.

◆ unwrap() [2/2]

template<class TYPE >
bslalg::NothrowMovableWrapper< TYPE >::ValueType const & bslalg::NothrowMovableWrapper< TYPE >::unwrap ( ) const
inline

◆ ~NothrowMovableWrapper()

template<class TYPE >
bslalg::NothrowMovableWrapper< TYPE >::~NothrowMovableWrapper ( )
inline