25 KiB
[polymorphic]
20 Memory management library [mem]
20.4 Types for composite class design [mem.composite.types]
20.4.2 Class template polymorphic [polymorphic]
20.4.2.1 General [polymorphic.general]
A polymorphic object manages the lifetime of an owned object.
A polymorphic object may own objects of different types at different points in its lifetime.
A polymorphic object isvalueless if it has no owned object.
A polymorphic object may become valueless only after it has been moved from.
In every specialization polymorphic<T, Allocator>, if the type allocator_traits::value_type is not the same type as T, the program is ill-formed.
Every object of type polymorphic<T, Allocator> uses an object of type Allocator to allocate and free storage for the owned object as needed.
Constructing an owned object of type U with args... using the allocator a means callingallocator_traits::construct(a, p, args...) whereargs is an expression pack,a is an allocator, andp points to storage suitable for an owned object of type U.
The member alloc is used for any memory allocation and element construction performed by member functions during the lifetime of each polymorphic value object, or until the allocator is replaced.
The allocator may be replaced only via assignment or swap().
Allocator replacement is performed by copy assignment, move assignment, or swapping of the allocator only if ([container.reqmts]):
allocator_traits::propagate_on_container_copy_assignment::value, or
allocator_traits::propagate_on_container_move_assignment::value, or
allocator_traits::propagate_on_container_swap::value
is true within the implementation of the corresponding polymorphic operation.
A program that instantiates the definition of polymorphic for a non-object type, an array type,in_place_t, a specialization of in_place_type_t, or a cv-qualified type is ill-formed.
The template parameter T of polymorphic may be an incomplete type.
The template parameter Allocator of polymorphic shall meet the requirements of Cpp17Allocator.
If a program declares an explicit or partial specialization of polymorphic, the behavior is undefined.
20.4.2.2 Synopsis [polymorphic.syn]
namespace std {template<class T, class Allocator = allocator>class polymorphic {public:using value_type = T; using allocator_type = Allocator; using pointer = typename allocator_traits::pointer; using const_pointer = typename allocator_traits::const_pointer; // [polymorphic.ctor], constructorsconstexpr explicit polymorphic(); constexpr explicit polymorphic(allocator_arg_t, const Allocator& a); constexpr polymorphic(const polymorphic& other); constexpr polymorphic(allocator_arg_t, const Allocator& a, const polymorphic& other); constexpr polymorphic(polymorphic&& other) noexcept; constexpr polymorphic(allocator_arg_t, const Allocator& a, polymorphic&& other)noexcept(see below); templateconstexpr explicit polymorphic(U&& u); templateconstexpr explicit polymorphic(allocator_arg_t, const Allocator& a, U&& u); template<class U, class... Ts>constexpr explicit polymorphic(in_place_type_t, Ts&&... ts); template<class U, class... Ts>constexpr explicit polymorphic(allocator_arg_t, const Allocator& a, in_place_type_t, Ts&&... ts); template<class U, class I, class... Us>constexpr explicit polymorphic(in_place_type_t, initializer_list ilist, Us&&... us); template<class U, class I, class... Us>constexpr explicit polymorphic(allocator_arg_t, const Allocator& a, in_place_type_t, initializer_list ilist, Us&&... us); // [polymorphic.dtor], destructorconstexpr ~polymorphic(); // [polymorphic.assign], assignmentconstexpr polymorphic& operator=(const polymorphic& other); constexpr polymorphic& operator=(polymorphic&& other) noexcept(see below); // [polymorphic.obs], observersconstexpr const T& operator*() const noexcept; constexpr T& operator*() noexcept; constexpr const_pointer operator->() const noexcept; constexpr pointer operator->() noexcept; constexpr bool valueless_after_move() const noexcept; constexpr allocator_type get_allocator() const noexcept; // [polymorphic.swap], swapconstexpr void swap(polymorphic& other) noexcept(see below); friend constexpr void swap(polymorphic& lhs, polymorphic& rhs) noexcept(see below); private: Allocator alloc = Allocator(); // exposition only};}
20.4.2.3 Constructors [polymorphic.ctor]
The following element applies to all functions in [polymorphic.ctor]:
Throws: Nothing unless allocator_traits::allocate orallocator_traits::construct throws.
constexpr explicit polymorphic();
Constraints: is_default_constructible_v is true.
Mandates:
is_default_constructible_v is true, and
is_copy_constructible_v is true.
Effects: Constructs an owned object of type T with an empty argument list using the allocator alloc.
constexpr explicit polymorphic(allocator_arg_t, const Allocator& a);
Mandates:
is_default_constructible_v is true, and
is_copy_constructible_v is true.
Effects: alloc is direct-non-list-initialized with a.
Constructs an owned object of type T with an empty argument list using the allocator alloc.
constexpr polymorphic(const polymorphic& other);
Effects: alloc is direct-non-list-initialized withallocator_traits::select_on_container_copy_construction(other.alloc).
If other is valueless, *this is valueless.
Otherwise, constructs an owned object of type U, whereU is the type of the owned object in other, with the owned object in other using the allocator alloc.
constexpr polymorphic(allocator_arg_t, const Allocator& a, const polymorphic& other);
Effects: alloc is direct-non-list-initialized with a.
If other is valueless, *this is valueless.
Otherwise, constructs an owned object of type U, whereU is the type of the owned object in other, with the owned object in other using the allocator alloc.
constexpr polymorphic(polymorphic&& other) noexcept;
Effects: alloc is direct-non-list-initialized withstd::move(other.alloc).
If other is valueless, *this is valueless.
Otherwise, either *this takes ownership of the owned object of other or, owns an object of the same type constructed from the owned object of other considering that owned object as an rvalue, using the allocator alloc.
constexpr polymorphic(allocator_arg_t, const Allocator& a, polymorphic&& other) noexcept(allocator_traits<Allocator>::is_always_equal::value);
Effects: alloc is direct-non-list-initialized with a.
If other is valueless, *this is valueless.
Otherwise, if alloc == other.alloc is true, either constructs an object of type polymorphic that owns the owned object of other, making other valueless; or, owns an object of the same type constructed from the owned object of other considering that owned object as an rvalue.
Otherwise, if alloc != other.alloc is true, constructs an object of type polymorphic, considering the owned object in other as an rvalue, using the allocator alloc.
template<class U = T> constexpr explicit polymorphic(U&& u);
Constraints: Where UU is remove_cvref_t,
is_same_v<UU, polymorphic> is false,
derived_from<UU, T> is true,
is_constructible_v<UU, U> is true,
is_copy_constructible_v is true,
UU is not a specialization of in_place_type_t, and
is_default_constructible_v is true.
Effects: Constructs an owned object of type UU with std::forward(u) using the allocator alloc.
template<class U = T> constexpr explicit polymorphic(allocator_arg_t, const Allocator& a, U&& u);
Constraints: Where UU is remove_cvref_t,
is_same_v<UU, polymorphic> is false,
derived_from<UU, T> is true,
is_constructible_v<UU, U> is true,
is_copy_constructible_v is true, and
UU is not a specialization of in_place_type_t.
Effects: alloc is direct-non-list-initialized with a.
Constructs an owned object of type UU with std::forward(u) using the allocator alloc.
template<class U, class... Ts> constexpr explicit polymorphic(in_place_type_t<U>, Ts&&... ts);
Constraints:
is_same_v<remove_cvref_t, U> is true,
derived_from<U, T> is true,
is_constructible_v<U, Ts...> is true,
is_copy_constructible_v is true, and
is_default_constructible_v is true.
Effects: Constructs an owned object of type U withstd::forward(ts)... using the allocator alloc.
template<class U, class... Ts> constexpr explicit polymorphic(allocator_arg_t, const Allocator& a, in_place_type_t<U>, Ts&&... ts);
Constraints:
is_same_v<remove_cvref_t, U> is true,
derived_from<U, T> is true,
is_constructible_v<U, Ts...> is true, and
is_copy_constructible_v is true.
Effects: alloc is direct-non-list-initialized with a.
Constructs an owned object of type U withstd::forward(ts)... using the allocator alloc.
template<class U, class I, class... Us> constexpr explicit polymorphic(in_place_type_t<U>, initializer_list<I> ilist, Us&&... us);
Constraints:
is_same_v<remove_cvref_t, U> is true,
derived_from<U, T> is true,
is_constructible_v<U, initializer_list&, Us...> is true,
is_copy_constructible_v is true, and
is_default_constructible_v is true.
Effects: Constructs an owned object of type U with the arguments ilist, std::forward(us)... using the allocator alloc.
template<class U, class I, class... Us> constexpr explicit polymorphic(allocator_arg_t, const Allocator& a, in_place_type_t<U>, initializer_list<I> ilist, Us&&... us);
Constraints:
is_same_v<remove_cvref_t, U> is true,
derived_from<U, T> is true,
is_constructible_v<U, initializer_list&, Us...> is true, and
is_copy_constructible_v is true.
Effects: alloc is direct-non-list-initialized with a.
Constructs an owned object of type U with the argumentsilist, std::forward(us)... using the allocator alloc.
20.4.2.4 Destructor [polymorphic.dtor]
constexpr ~polymorphic();
Mandates: T is a complete type.
Effects: If *this is not valueless, destroys the owned object using allocator_traits::destroy and then the storage is deallocated.
20.4.2.5 Assignment [polymorphic.assign]
constexpr polymorphic& operator=(const polymorphic& other);
Mandates: T is a complete type.
Effects: If addressof(other) == this is true, there are no effects.
Otherwise:
-
The allocator needs updating ifallocator_traits::propagate_on_container_copy_assignment::value is true.
-
If other is not valueless, a new owned object is constructed in *this usingallocator_traits::construct with the owned object from other as the argument, using either the allocator in *this or the allocator in other if the allocator needs updating.
-
The previously owned object in *this, if any, is destroyed using allocator_traits::
destroy and then the storage is deallocated. -
If the allocator needs updating, the allocator in *this is replaced with a copy of the allocator in other.
Returns: A reference to *this.
Remarks: If any exception is thrown, there are no effects on *this.
constexpr polymorphic& operator=(polymorphic&& other) noexcept(allocator_traits<Allocator>::propagate_on_container_move_assignment::value || allocator_traits<Allocator>::is_always_equal::value);
Mandates: If allocator_traits::is_always_equal::value is false,T is a complete type.
Effects: If addressof(other) == this is true, there are no effects.
Otherwise:
-
The allocator needs updating ifallocator_traits::propagate_on_container_move_assignment::value is true.
-
If alloc == other.alloc is true, swaps the owned objects in *this and other; the owned object in other, if any, is then destroyed using allocator_traits::destroy and then the storage is deallocated.
-
Otherwise, if alloc != other.alloc is true; if other is not valueless, a new owned object is constructed in *this using allocator_traits::construct with the owned object from other as the argument as an rvalue, using either the allocator in *this or the allocator in other if the allocator needs updating.
-
The previously owned object in *this, if any, is destroyed using allocator_traits::
destroy and then the storage is deallocated. -
If the allocator needs updating, the allocator in *this is replaced with a copy of the allocator in other.
Returns: A reference to *this.
Remarks: If any exception is thrown, there are no effects on *this or other.
20.4.2.6 Observers [polymorphic.obs]
constexpr const T& operator*() const noexcept; constexpr T& operator*() noexcept;
Preconditions: *this is not valueless.
Returns: A reference to the owned object.
constexpr const_pointer operator->() const noexcept; constexpr pointer operator->() noexcept;
Preconditions: *this is not valueless.
Returns: A pointer to the owned object.
constexpr bool valueless_after_move() const noexcept;
Returns: true if *this is valueless, otherwise false.
constexpr allocator_type get_allocator() const noexcept;
Returns: alloc.
20.4.2.7 Swap [polymorphic.swap]
constexpr void swap(polymorphic& other) noexcept(allocator_traits<Allocator>::propagate_on_container_swap::value || allocator_traits<Allocator>::is_always_equal::value);
Preconditions: If allocator_traits::propagate_on_container_swap::value is true, thenAllocator meets the Cpp17Swappable requirements.
Otherwise get_allocator() == other.
get_allocator() is true.
Effects: Swaps the states of *this and other, exchanging owned objects or valueless states.
If allocator_traits::propagate_on_container_swap::value is true, then the allocators of *this and other are exchanged by calling swap as described in [swappable.requirements].
Otherwise, the allocators are not swapped.
[Note 1:
Does not call swap on the owned objects directly.
â end note]
constexpr void swap(polymorphic& lhs, polymorphic& rhs) noexcept(noexcept(lhs.swap(rhs)));
Effects: Equivalent to lhs.swap(rhs).