Quick Links:

bal | bbl | bdl | bsl

Namespaces | Defines | Functions

Component bslalg_nothrowmovablewrapper
[Package bslalg]

Provide a wrapper that asserts a noexcept move constructor. More...

Namespaces

namespace  bslalg
namespace  bsl

Defines

#define Function_NothrowWrapper   bsl_deprecated::NothrowMovableWrapper

Functions

 bslalg::NothrowMovableWrapper::NothrowMovableWrapper ()
 bslalg::NothrowMovableWrapper::NothrowMovableWrapper (bsl::allocator_arg_t, const allocator_type &alloc)
 bslalg::NothrowMovableWrapper::NothrowMovableWrapper (const TYPE &val)
 bslalg::NothrowMovableWrapper::NothrowMovableWrapper (bsl::allocator_arg_t, const allocator_type &alloc, const TYPE &val)
 bslalg::NothrowMovableWrapper::NothrowMovableWrapper (bslmf::MovableRef< TYPE > val)
 bslalg::NothrowMovableWrapper::NothrowMovableWrapper (bsl::allocator_arg_t, const allocator_type &alloc, bslmf::MovableRef< TYPE > val)
 bslalg::NothrowMovableWrapper::NothrowMovableWrapper (const NothrowMovableWrapper &original)
 bslalg::NothrowMovableWrapper::NothrowMovableWrapper (bsl::allocator_arg_t, const allocator_type &alloc, const NothrowMovableWrapper &original)
 bslalg::NothrowMovableWrapper::NothrowMovableWrapper (bslmf::MovableRef< NothrowMovableWrapper > original) BSLS_KEYWORD_NOEXCEPT
 bslalg::NothrowMovableWrapper::NothrowMovableWrapper (bsl::allocator_arg_t, const allocator_type &alloc, bslmf::MovableRef< NothrowMovableWrapper > original)
 bslalg::NothrowMovableWrapper::~NothrowMovableWrapper ()
ValueType & bslalg::NothrowMovableWrapper::unwrap ()
allocator_type bslalg::NothrowMovableWrapper::get_allocator () const
ValueType const & bslalg::NothrowMovableWrapper::unwrap () const

Detailed Description

Outline
Purpose:
Provide a wrapper that asserts a noexcept move constructor.
Classes:
bslalg::NothrowMovableWrapper wrapper class with noexcept move constructor
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
      bsl::conditional<bsl::is_nothrow_move_constructible<TP>::value,
                       bslmf::MovableRef<TP>, const TP&>::type
      MoveIfNoexcept(TP& x);
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
      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; }
  };
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
  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);
  }
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;
  }
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; }
  };
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> >
          obj4(bslmf::MovableRefUtil::move(obj3));
      assert(-1 == obj3.value().unwrap().value());  // moved from
      assert(3 == obj4.value().unwrap().value());
  }

Define Documentation

#define Function_NothrowWrapper   bsl_deprecated::NothrowMovableWrapper

Function Documentation

template<class TYPE >
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper (  )  [inline, inherited]
template<class TYPE >
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().

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

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.

References bsls::ObjectBuffer< TYPE >::address(), and bslma::ConstructionUtil::construct().

template<class TYPE >
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper ( bslmf::MovableRef< TYPE >  val  )  [inline, inherited]

IMPLICIT: Wrap the specified val, using TYPEs move constructor.

References bsls::ObjectBuffer< TYPE >::address(), bslma::ConstructionUtil::construct(), and bslmf::MovableRefUtil::move().

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

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.

References bsls::ObjectBuffer< TYPE >::address(), bslma::ConstructionUtil::construct(), and bslmf::MovableRefUtil::move().

template<class TYPE >
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper ( const NothrowMovableWrapper< TYPE > &  original  )  [inline, inherited]

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

References bsls::ObjectBuffer< TYPE >::address(), bslma::ConstructionUtil::construct(), and bslalg::NothrowMovableWrapper< TYPE >::unwrap().

template<class TYPE >
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 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.

References bsls::ObjectBuffer< TYPE >::address(), bslma::ConstructionUtil::construct(), and bslalg::NothrowMovableWrapper< TYPE >::unwrap().

template<class TYPE >
bslalg::NothrowMovableWrapper< TYPE >::NothrowMovableWrapper ( bslmf::MovableRef< NothrowMovableWrapper< TYPE > >  original  )  [inline, inherited]

IMPLICIT: Move construct from the specified original wrapper using TYPEs 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().

template<class TYPE >
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 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.

References bslmf::MovableRefUtil::access(), bsls::ObjectBuffer< TYPE >::address(), bslma::ConstructionUtil::construct(), bslmf::MovableRefUtil::move(), and bslalg::NothrowMovableWrapper< TYPE >::unwrap().

template<class TYPE >
bslalg::NothrowMovableWrapper< TYPE >::~NothrowMovableWrapper (  )  [inline, inherited]

Destroy this object, invoking TYPEs destructor.

References bsls::ObjectBuffer< TYPE >::object().

template<class TYPE >
bslalg::NothrowMovableWrapper< TYPE >::ValueType & bslalg::NothrowMovableWrapper< TYPE >::unwrap (  )  [inline, inherited]
template<class TYPE >
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().

template<class TYPE >
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().