BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bslalg_nothrowmovablewrapper.h
Go to the documentation of this file.
1/// @file bslalg_nothrowmovablewrapper.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslalg_nothrowmovablewrapper.h -*-C++-*-
8#ifndef INCLUDED_BSLALG_NOTHROWMOVABLEWRAPPER
9#define INCLUDED_BSLALG_NOTHROWMOVABLEWRAPPER
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslalg_nothrowmovablewrapper bslalg_nothrowmovablewrapper
15/// @brief Provide a wrapper that asserts a noexcept move constructor.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslalg
19/// @{
20/// @addtogroup bslalg_nothrowmovablewrapper
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslalg_nothrowmovablewrapper-purpose"> Purpose</a>
25/// * <a href="#bslalg_nothrowmovablewrapper-classes"> Classes </a>
26/// * <a href="#bslalg_nothrowmovablewrapper-description"> Description </a>
27/// * <a href="#bslalg_nothrowmovablewrapper-usage"> Usage </a>
28/// * <a href="#bslalg_nothrowmovablewrapper-example-1"> Example 1 </a>
29///
30/// # Purpose {#bslalg_nothrowmovablewrapper-purpose}
31/// Provide a wrapper that asserts a noexcept move constructor.
32///
33/// # Classes {#bslalg_nothrowmovablewrapper-classes}
34///
35/// - bslalg::NothrowMovableWrapper: wrapper class with noexcept move constructor
36///
37/// @see bslalg_movablewrapperutil
38///
39/// # Description {#bslalg_nothrowmovablewrapper-description}
40/// This component provides a wrapper class template
41/// `bslalg::NothrowMovableWrapper<TYPE>` holding an object of `TYPE` and
42/// providing no other functionality other than returning the wrapped object.
43/// The use of this class communicates to specific clients (see
44/// @ref bslstl_function ) that the wrapped object should be treated as-if it has a
45/// `noexcept` move constructor, even in C++03, where `noexcept` does not exist.
46/// The client might, for example, move the object using efficient,
47/// non-exception-safe logic rather than, e.g., copying the object or storing it
48/// in heap memory so that its pointer can be moved. The behavior is undefined
49/// if the move constructor is invoked and *does* throw; typically resulting in
50/// `terminate` being invoked.
51///
52/// ## Usage {#bslalg_nothrowmovablewrapper-usage}
53///
54///
55///
56/// ### Example 1 {#bslalg_nothrowmovablewrapper-example-1}
57///
58///
59/// In this example, we define a class template, `CountedType<TYPE>`, a wrapper
60/// around `TYPE` that counts the number of extant `CountedType` objects. We
61/// begin by defining the static count member along with the single value
62/// member:
63/// @code
64/// template <class TYPE>
65/// class CountedType {
66/// // CLASS DATA
67/// static int s_count;
68///
69/// // DATA
70/// TYPE d_value;
71/// @endcode
72/// Because of externally-imposed requirements, the move constructor for
73/// `CountedType` must provide the strong guarantee; i.e., if the move
74/// constructor of `TYPE` throws an exception, then the moved-from `CountedType`
75/// object must be left unchanged. To support this requirement, we next define
76/// a private static function, `MoveIfNoexcept`, similar to the standard
77/// `std::move_if_noexcept`, that returns a movable reference if its argument is
78/// no-throw move constructible and a const lvalue reference otherwise:
79/// @code
80/// // PRIVATE CLASS FUNCTIONS
81/// template <class TP>
82/// static typename
83/// bsl::conditional<bsl::is_nothrow_move_constructible<TP>::value,
84/// bslmf::MovableRef<TP>, const TP&>::type
85/// MoveIfNoexcept(TP& x);
86/// @endcode
87/// We next finish out the class definition with a constructor, copy
88/// constructor, move constructor, destructor, and member functions to retrieve
89/// the count and value:
90/// @code
91/// public:
92/// // CLASS FUNCTIONS
93///
94/// static int count() { return s_count; }
95///
96/// // CREATORS
97///
98/// /// Construct `CountedType` from the specified `val`.
99/// CountedType(const TYPE& val);
100///
101/// // Copy construct `*this` from the specified `original` object.
102/// CountedType(const CountedType& original);
103///
104/// // Move construct `*this` from `original`. If an exception is
105/// // thrown, by the constructor for `TYPE` `original` is unchanged.
106/// CountedType(bslmf::MovableRef<CountedType> original);
107///
108/// /// Destroy this object.
109/// ~CountedType() { --s_count; }
110///
111/// // MANIPULATORS
112///
113/// TYPE& value() { return d_value; }
114///
115/// // ACCESSORS
116///
117/// const TYPE& value() const { return d_value; }
118/// };
119/// @endcode
120/// Next, we implement `MoveIfNoexcept`, which calls `move` on its argument,
121/// allowing it to convert back to an lvalue if the return type is an lvalue
122/// reference:
123/// @code
124/// template <class TYPE>
125/// template <class TP>
126/// inline typename
127/// bsl::conditional<bsl::is_nothrow_move_constructible<TP>::value,
128/// bslmf::MovableRef<TP>, const TP&>::type
129/// CountedType<TYPE>::MoveIfNoexcept(TP& x)
130/// {
131/// return bslmf::MovableRefUtil::move(x);
132/// }
133/// @endcode
134/// Next, we implement the value constructor and copy constructor, which simply
135/// copy their argument into the `d_value` data members and increment the count:
136/// @code
137/// template <class TYPE>
138/// CountedType<TYPE>::CountedType(const TYPE& val) : d_value(val)
139/// {
140/// ++s_count;
141/// }
142///
143/// template <class TYPE>
144/// CountedType<TYPE>::CountedType(const CountedType& original)
145/// : d_value(original.d_value)
146/// {
147/// ++s_count;
148/// }
149/// @endcode
150/// We're now ready implement the move constructor. Logically, we would simply
151/// move the value from `original` into the `d_value` member of `*this`, but an
152/// exception thrown by `TYPE`s move constructor would leave `original` in a
153/// (valid but) unspecified state, violating the strong guarantee. Instead, we
154/// move the value only if we know that the move will succeed; otherwise, we
155/// copy it. This behavior is facilitated by the `MoveIfNoexcept` function
156/// defined above:
157/// @code
158/// template <class TYPE>
159/// CountedType<TYPE>::CountedType(bslmf::MovableRef<CountedType> original)
160/// : d_value(
161/// MoveIfNoexcept(bslmf::MovableRefUtil::access(original).d_value))
162/// {
163/// ++s_count;
164/// }
165/// @endcode
166/// Finally, we define the `s_count` member to complete the class
167/// implementation:
168/// @code
169/// template <class TYPE>
170/// int CountedType<TYPE>::s_count = 0;
171/// @endcode
172/// To test the `CountedType` class template, assume a simple client type,
173/// `SomeType` that makes it easy to detect if it was move constructed.
174/// `SomeType` holds an `int` value that is set to -1 when it is moved from, as
175/// shown here:
176/// @code
177/// class SomeType {
178/// int d_value;
179/// public:
180/// SomeType(int v = 0) : d_value(v) { } // IMPLICIT
181/// SomeType(const SomeType& original) : d_value(original.d_value) { }
182/// SomeType(bslmf::MovableRef<SomeType> original)
183/// : d_value(bslmf::MovableRefUtil::access(original).d_value)
184/// { bslmf::MovableRefUtil::access(original).d_value = -1; }
185///
186/// int value() const { return d_value; }
187/// };
188/// @endcode
189/// Notice that `SomeType` neglected to declare its move constructor as
190/// `noexcept`. This might be an oversight or it could be an old class that
191/// predates both `noexcept` and the `bsl::is_nothrow_move_constructible` trait.
192/// It is even be possible that the move constructor might throw (though, of
193/// course, it doesn't in this simplified example). Regardless, the effect is
194/// that move-constructing a `CountedType<SomeType>` will result in the move
195/// constructor actually performing a copy:
196/// @code
197/// void main()
198/// {
199/// CountedType<SomeType> obj1(1);
200/// CountedType<SomeType> obj2(bslmf::MovableRefUtil::move(obj1));
201/// assert(1 == obj1.value().value()); // Copied, not moved from
202/// assert(1 == obj2.value().value());
203/// @endcode
204/// For the purpose of this example, we can be sure that `SomeThing` will not
205/// throw on move, at least not in our application. In order to obtain the
206/// expected move optimization, we next wrap our 'SomeType in a
207/// `bslalg::NothrowMovableWrapper`:
208/// @code
209/// CountedType<bslalg::NothrowMovableWrapper<SomeType> >
210/// obj3(SomeType(3));
211/// CountedType<bslalg::NothrowMovableWrapper<SomeType> >
212/// obj4(bslmf::MovableRefUtil::move(obj3));
213/// assert(-1 == obj3.value().unwrap().value()); // moved from
214/// assert(3 == obj4.value().unwrap().value());
215/// }
216/// @endcode
217/// @}
218/** @} */
219/** @} */
220
221/** @addtogroup bsl
222 * @{
223 */
224/** @addtogroup bslalg
225 * @{
226 */
227/** @addtogroup bslalg_nothrowmovablewrapper
228 * @{
229 */
230
231#include <bslscm_version.h>
232
234#include <bslma_bslallocator.h>
236
237#include <bslmf_allocatorargt.h>
238#include <bslmf_assert.h>
239#include <bslmf_conditional.h>
240#include <bslmf_isarray.h>
241#include <bslmf_isfunction.h>
243#include <bslmf_movableref.h>
246
247#include <bsls_keyword.h>
248#include <bsls_objectbuffer.h>
249
250
251
252namespace bslalg {
253
254 // ====================================
255 // class template NothrowMovableWrapper
256 // ====================================
257
258/// An object of this type wraps a value of the specified `TYPE`, and
259/// provides no other functionality other than returning the wrapped object.
260/// The move constructor is guaranteed not to throw, even if the move
261/// constructor for `TYPE` has no such guarantee. The user is thus
262/// asserting that the move constructor for the wrapped object *will not*
263/// throw, even if it is allowed to. Constraints: this class can be
264/// instantiated on object types only, i.e., not references, arrays, or
265/// function types (though function pointers are OK).
266///
267/// See @ref bslalg_nothrowmovablewrapper
268template <class TYPE>
270
271 // Cannot wrap reference types, array types, or function types.
275
276 // PRIVATE TYPES
277
278 /// Private type that prevents allocator-argument overloads from
279 /// participating in overload resolution if `TYPE` is not allocator
280 /// aware. Does not meet the allocator requirements (or any other
281 /// requirements) and cannot be constructed by users.
282 ///
283 /// See @ref bslalg_nothrowmovablewrapper
284 struct DummyAllocator {
285 };
286
288
289 typedef typename bsl::remove_cv<TYPE>::type StoredType;
290
291 // DATA
293
294 private:
295 // NOT IMPLEMENTED
296
297 /// Not assignable.
298 NothrowMovableWrapper& operator=(
300
301 public:
302 // TRAITS
305
309
310 // If this wrapper is allocator-aware (because 'TYPE' is allocator-aware),
311 // then choose the leading-allocator convention.
315
319
320 // TYPES
321
322 /// Type of allocator to use. If `TYPE` is not allocator-aware, then
323 /// this is a private dummy type that will disable use of any
324 /// constructor that takes an allocator.
327 DummyAllocator>::type allocator_type;
328
329 typedef TYPE ValueType;
330
331 // CREATORS
332
333 /// Value-initialize the object wrapped by `*this`. For allocator-aware
334 /// `TYPE`, optionally specify an `alloc` (e.g., the address of a
335 /// `bslma::Allocator` object) to supply memory; otherwise, the default
336 /// allocator is used.
339
340 /// Wrap the specified `val`, using `TYPE`s (possibly extended) copy
341 /// constructor. For allocator-aware `TYPE`, optionally specify an
342 /// `alloc` (e.g., the address of a `bslma::Allocator` object) to supply
343 /// memory; otherwise, the default allocator is used.
344 NothrowMovableWrapper(const TYPE& val); // IMPLICIT
346 const allocator_type& alloc,
347 const TYPE& val);
348
349 /// Wrap the specified `val`, using `TYPE`s move constructor.
351
352 /// Wrap the specified `val`, using `TYPE`s extended move constructor.
353 /// Use the specified `alloc` (e.g., the address of a `bslma::Allocator` object) to supply memory.
354 ///
355 /// \note Note that this constructor will not be
356 /// selected by overload resolution unless `TYPE` is allocator aware.
358 const allocator_type& alloc,
360
361 /// Copy construct from the specified `original` wrapper using `TYPE`s
362 /// copy constructor.
364
365 /// Copy construct from the specified `original` wrapper using `TYPE`s
366 /// extended copy constructor. Use the specified `alloc` (e.g., the
367 /// address of a `bslma::Allocator` object) to supply memory.
368 ///
369 /// \note Note that this constructor will not be selected by overload resolution unless
370 /// `TYPE` is allocator aware.
372 const allocator_type& alloc,
373 const NothrowMovableWrapper& original);
374
377 // IMPLICIT
378 // Move construct from the specified 'original' wrapper using 'TYPE's
379 // move constructor. Note that this move constructor is
380 // unconditionally 'noexcept', as that is the entire purpose of this
381 // wrapper.
382
383 /// Move construct from the specified `original` wrapper using `TYPE`s
384 /// extended move constructor. Use the specified `alloc` (e.g., the
385 /// address of a `bslma::Allocator` object) to supply memory.
386 ///
387 /// \note Note that this constructor will not be selected by overload resolution unless
388 /// `TYPE` is allocator aware.
390 const allocator_type& alloc,
392
393 /// Destroy this object, invoking `TYPE`s destructor.
395
396 // MANIPULATORS
397
398 /// Return a reference offering modifiable access to the wrapped
399 /// object.
400 ValueType& unwrap();
401
402 /// Return a reference offering modifiable access to the wrapped
403 /// object.
404 operator ValueType&()
405 {
406 // Must be in-place inline to work around MSVC 2013 bug.
407 return unwrap();
408 }
409
410 // ACCESSORS
411
412 /// Return the allocator used to construct this object.
413 /// \note Note that this
414 /// method will fail to instantiate unless `TYPE` is allocator-aware.
416
417 /// Return a reference offering const access to the wrapped object.
418 ValueType const& unwrap() const;
419
420 /// Return a reference offering const access to the wrapped object.
421 operator ValueType const&() const
422 {
423 // Must be in-place inline to work around MSVC 2013 bug.
424 return unwrap();
425 }
426};
427
428/// This specialization is for wrapped types. We do not support wrapping a
429/// wrapped type.
430template <class TYPE>
432 BSLMF_ASSERT(!sizeof(TYPE) && "Cannot wrap a wrapped object");
433};
434
435/// This specialization is for wrapped types. We do not support wrapping a
436/// wrapped type.
437template <class TYPE>
439 BSLMF_ASSERT(!sizeof(TYPE) && "Cannot wrap a wrapped object");
440};
441
442} // close package namespace
443
444 // ------------------------------------
445 // class template NothrowMovableWrapper
446 // ------------------------------------
447
448// CREATORS
449template <class TYPE>
450inline
455
456template <class TYPE>
457inline
464
465template <class TYPE>
466inline
468{
469 bslma::ConstructionUtil::construct(d_buffer.address(), (void *)0, val);
470}
471
472template <class TYPE>
473inline
476 const allocator_type& alloc,
477 const TYPE& val)
478{
479 bslma::ConstructionUtil::construct(d_buffer.address(), alloc, val);
480}
481
482template <class TYPE>
483inline
490
491template <class TYPE>
492inline
502
503template <class TYPE>
504inline
506 const NothrowMovableWrapper& original)
507{
509 d_buffer.address(), (void *)0, original.unwrap());
510}
511
512template <class TYPE>
513inline
516 const allocator_type& alloc,
517 const NothrowMovableWrapper& original)
518{
520 d_buffer.address(), alloc, original.unwrap());
521}
522
523template <class TYPE>
524inline
534
535template <class TYPE>
536inline
548
549template <class TYPE>
550inline
552{
553 d_buffer.object().~TYPE();
554}
555
556// MANIPULATORS
557template <class TYPE>
558inline
561{
562 return d_buffer.object();
563}
564
565// ACCESSORS
566template <class TYPE>
567inline
570{
571 return d_buffer.object().allocator();
572}
573
574template <class TYPE>
575inline
578{
579 return d_buffer.object();
580}
581
582
583
584#endif // ! defined(INCLUDED_BSLALG_NOTHROWMOVABLEWRAPPER)
585
586// ----------------------------------------------------------------------------
587// Copyright 2020 Bloomberg Finance L.P.
588//
589// Licensed under the Apache License, Version 2.0 (the "License");
590// you may not use this file except in compliance with the License.
591// You may obtain a copy of the License at
592//
593// http://www.apache.org/licenses/LICENSE-2.0
594//
595// Unless required by applicable law or agreed to in writing, software
596// distributed under the License is distributed on an "AS IS" BASIS,
597// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
598// See the License for the specific language governing permissions and
599// limitations under the License.
600// ----------------------------- END-OF-FILE ----------------------------------
601
602/** @} */
603/** @} */
604/** @} */
Definition bslma_bslallocator.h:588
Definition bslalg_nothrowmovablewrapper.h:269
BSLMF_NESTED_TRAIT_DECLARATION(NothrowMovableWrapper, bsl::is_nothrow_move_constructible)
BSLMF_NESTED_TRAIT_DECLARATION_IF(NothrowMovableWrapper, bslmf::IsBitwiseMoveable, bslmf::IsBitwiseMoveable< TYPE >::value)
TYPE ValueType
Definition bslalg_nothrowmovablewrapper.h:329
BSLMF_NESTED_TRAIT_DECLARATION_IF(NothrowMovableWrapper, bslma::UsesBslmaAllocator, bslma::UsesBslmaAllocator< TYPE >::value)
bsl::conditional< bslma::UsesBslmaAllocator< TYPE >::value, bsl::allocator< char >, DummyAllocator >::type allocator_type
Definition bslalg_nothrowmovablewrapper.h:327
BSLMF_NESTED_TRAIT_DECLARATION_IF(NothrowMovableWrapper, bslmf::UsesAllocatorArgT, bslma::UsesBslmaAllocator< TYPE >::value)
Definition bslmf_movableref.h:752
~NothrowMovableWrapper()
Destroy this object, invoking TYPEs destructor.
Definition bslalg_nothrowmovablewrapper.h:551
NothrowMovableWrapper()
Definition bslalg_nothrowmovablewrapper.h:451
ValueType & unwrap()
Definition bslalg_nothrowmovablewrapper.h:560
allocator_type get_allocator() const
Definition bslalg_nothrowmovablewrapper.h:569
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:231
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_KEYWORD_DELETED
Definition bsls_keyword.h:651
#define BSLS_KEYWORD_NOEXCEPT
Definition bsls_keyword.h:674
Definition bdlc_flathashmap.h:2218
Definition bslmf_allocatorargt.h:433
Definition bslmf_conditional.h:123
Definition bslmf_integralconstant.h:261
Definition bslmf_isarray.h:168
Definition bslmf_isfunction.h:232
Definition bslmf_isnothrowmoveconstructible.h:361
remove_const< typenameremove_volatile< t_TYPE >::type >::type type
Definition bslmf_removecv.h:128
static void construct(TARGET_TYPE *address, const ALLOCATOR &allocator)
Definition bslma_constructionutil.h:1244
Definition bslma_usesbslmaallocator.h:344
Definition bslmf_isbitwisemoveable.h:718
Definition bslmf_movableref.h:821
Definition bslmf_movableref.h:795
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1067
static t_TYPE & access(t_TYPE &ref) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1039
Definition bslmf_usesallocatorargt.h:100
Definition bsls_objectbuffer.h:277