BDE 4.14.0 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 struct DummyAllocator {
283 };
284
286
287 typedef typename bsl::remove_cv<TYPE>::type StoredType;
288
289 // DATA
291
292 // NOT IMPLEMENTED
293
294 /// Not assignable.
295 NothrowMovableWrapper& operator=(
297
298 public:
299 // TRAITS
302
306
307 // If this wrapper is allocator-aware (because 'TYPE' is allocator-aware),
308 // then choose the leading-allocator convention.
312
316
317 // TYPES
318
319 /// Type of allocator to use. If `TYPE` is not allocator-aware, then
320 /// this is a private dummy type that will disable use of any
321 /// constructor that takes an allocator.
324 DummyAllocator>::type allocator_type;
325
326 typedef TYPE ValueType;
327
328 // CREATORS
329
331 /// Value-initialize the object wrapped by `*this`. For allocator-aware
332 /// `TYPE`, optionally specify an `alloc` (e.g., the address of a
333 /// `bslma::Allocator` object) to supply memory; otherwise, the default
334 /// allocator is used.
335 NothrowMovableWrapper(bsl::allocator_arg_t, const allocator_type& alloc);
336
337 /// Wrap the specified `val`, using `TYPE`s (possibly extended) copy
338 /// constructor. For allocator-aware `TYPE`, optionally specify an
339 /// `alloc` (e.g., the address of a `bslma::Allocator` object) to supply
340 /// memory; otherwise, the default allocator is used.
341 NothrowMovableWrapper(const TYPE& val); // IMPLICIT
342 NothrowMovableWrapper(bsl::allocator_arg_t,
343 const allocator_type& alloc,
344 const TYPE& val);
345
346 /// Wrap the specified `val`, using `TYPE`s move constructor.
348
349 /// Wrap the specified `val`, using `TYPE`s extended move constructor.
350 /// Use the specified `alloc` (e.g., the address of a `bslma::Allocator`
351 /// object) to supply memory. Note that this constructor will not be
352 /// selected by overload resolution unless `TYPE` is allocator aware.
353 NothrowMovableWrapper(bsl::allocator_arg_t,
354 const allocator_type& alloc,
356
357 /// Copy construct from the specified `original` wrapper using `TYPE`s
358 /// copy constructor.
360
361 /// Copy construct from the specified `original` wrapper using `TYPE`s
362 /// extended copy constructor. Use the specified `alloc` (e.g., the
363 /// address of a `bslma::Allocator` object) to supply memory. Note that
364 /// this constructor will not be selected by overload resolution unless
365 /// `TYPE` is allocator aware.
366 NothrowMovableWrapper(bsl::allocator_arg_t,
367 const allocator_type& alloc,
368 const NothrowMovableWrapper& original);
369
372 // IMPLICIT
373 // Move construct from the specified 'original' wrapper using 'TYPE's
374 // move constructor. Note that this move constructor is
375 // unconditionally 'noexcept', as that is the entire purpose of this
376 // wrapper.
377
378 /// Move construct from the specified `original` wrapper using `TYPE`s
379 /// extended move constructor. Use the specified `alloc` (e.g., the
380 /// address of a `bslma::Allocator` object) to supply memory. Note that
381 /// this constructor will not be selected by overload resolution unless
382 /// `TYPE` is allocator aware.
383 NothrowMovableWrapper(bsl::allocator_arg_t,
384 const allocator_type& alloc,
386
387 /// Destroy this object, invoking `TYPE`s destructor.
389
390 // MANIPULATORS
391
392 /// Return a reference offering modifiable access to the wrapped
393 /// object.
394 ValueType& unwrap();
395
396 /// Return a reference offering modifiable access to the wrapped
397 /// object.
398 operator ValueType&()
399 {
400 // Must be in-place inline to work around MSVC 2013 bug.
401 return unwrap();
402 }
403
404 // ACCESSORS
405
406 /// Return the allocator used to construct this object. Note that this
407 /// method will fail to instantiate unless `TYPE` is allocator-aware.
409
410 /// Return a reference offering const access to the wrapped object.
411 ValueType const& unwrap() const;
412
413 /// Return a reference offering const access to the wrapped object.
414 operator ValueType const&() const
415 {
416 // Must be in-place inline to work around MSVC 2013 bug.
417 return unwrap();
418 }
419};
420
421/// This specialization is for wrapped types. We do not support wrapping a
422/// wrapped type.
423template <class TYPE>
425 BSLMF_ASSERT(!sizeof(TYPE) && "Cannot wrap a wrapped object");
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} // close package namespace
436
437 // ------------------------------------
438 // class template NothrowMovableWrapper
439 // ------------------------------------
440
441// CREATORS
442template <class TYPE>
443inline
448
449template <class TYPE>
450inline
452 bsl::allocator_arg_t,
453 const allocator_type& alloc)
454{
455 bslma::ConstructionUtil::construct(d_buffer.address(), alloc);
456}
457
458template <class TYPE>
459inline
461{
462 bslma::ConstructionUtil::construct(d_buffer.address(), (void *)0, val);
463}
464
465template <class TYPE>
466inline
468 bsl::allocator_arg_t,
469 const allocator_type& alloc,
470 const TYPE& val)
471{
472 bslma::ConstructionUtil::construct(d_buffer.address(), alloc, val);
473}
474
475template <class TYPE>
476inline
483
484template <class TYPE>
485inline
487 bsl::allocator_arg_t,
488 const allocator_type& alloc,
490{
491 bslma::ConstructionUtil::construct(d_buffer.address(),
492 alloc,
494}
495
496template <class TYPE>
497inline
499 const NothrowMovableWrapper& original)
500{
502 d_buffer.address(), (void *)0, original.unwrap());
503}
504
505template <class TYPE>
506inline
508 bsl::allocator_arg_t,
509 const allocator_type& alloc,
510 const NothrowMovableWrapper& original)
511{
513 d_buffer.address(), alloc, original.unwrap());
514}
515
516template <class TYPE>
517inline
527
528template <class TYPE>
529inline
531 bsl::allocator_arg_t,
532 const allocator_type& alloc,
534{
536 d_buffer.address(),
537 alloc,
539 bslmf::MovableRefUtil::access(original).unwrap()));
540}
541
542template <class TYPE>
543inline
545{
546 d_buffer.object().~TYPE();
547}
548
549// MANIPULATORS
550template <class TYPE>
551inline
554{
555 return d_buffer.object();
556}
557
558// ACCESSORS
559template <class TYPE>
560inline
563{
564 return d_buffer.object().allocator();
565}
566
567template <class TYPE>
568inline
571{
572 return d_buffer.object();
573}
574
575
576
577#endif // ! defined(INCLUDED_BSLALG_NOTHROWMOVABLEWRAPPER)
578
579// ----------------------------------------------------------------------------
580// Copyright 2020 Bloomberg Finance L.P.
581//
582// Licensed under the Apache License, Version 2.0 (the "License");
583// you may not use this file except in compliance with the License.
584// You may obtain a copy of the License at
585//
586// http://www.apache.org/licenses/LICENSE-2.0
587//
588// Unless required by applicable law or agreed to in writing, software
589// distributed under the License is distributed on an "AS IS" BASIS,
590// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
591// See the License for the specific language governing permissions and
592// limitations under the License.
593// ----------------------------- END-OF-FILE ----------------------------------
594
595/** @} */
596/** @} */
597/** @} */
Definition bslma_bslallocator.h:580
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:326
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:324
BSLMF_NESTED_TRAIT_DECLARATION_IF(NothrowMovableWrapper, bslmf::UsesAllocatorArgT, bslma::UsesBslmaAllocator< TYPE >::value)
Definition bslmf_movableref.h:751
~NothrowMovableWrapper()
Destroy this object, invoking TYPEs destructor.
Definition bslalg_nothrowmovablewrapper.h:544
NothrowMovableWrapper()
Definition bslalg_nothrowmovablewrapper.h:444
ValueType & unwrap()
Definition bslalg_nothrowmovablewrapper.h:553
allocator_type get_allocator() const
Definition bslalg_nothrowmovablewrapper.h:562
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:229
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_DELETED
Definition bsls_keyword.h:609
#define BSLS_KEYWORD_NOEXCEPT
Definition bsls_keyword.h:632
Definition bdlc_flathashmap.h:1805
Definition bslmf_conditional.h:120
Definition bslmf_integralconstant.h:244
Definition bslmf_isarray.h:168
Definition bslmf_isfunction.h:232
Definition bslmf_isnothrowmoveconstructible.h:358
remove_const< typenameremove_volatile< t_TYPE >::type >::type type
Definition bslmf_removecv.h:126
static void construct(TARGET_TYPE *address, const ALLOCATOR &allocator)
Definition bslma_constructionutil.h:1243
Definition bslma_usesbslmaallocator.h:343
Definition bslmf_isbitwisemoveable.h:718
Definition bslmf_movableref.h:817
Definition bslmf_movableref.h:791
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1060
static t_TYPE & access(t_TYPE &ref) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1032
Definition bslmf_usesallocatorargt.h:100
Definition bsls_objectbuffer.h:276