This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
indirect
unnecessarily requires copy constructionSection: 20.4.1.5 [indirect.asgn] Status: New Submitter: Jonathan Wakely Opened: 2025-05-01 Last modified: 2025-05-01
Priority: Not Prioritized
View all issues with New status.
Discussion:
The move assignment operator for indirect
says:
Mandates:However, the only way it ever construct an object is:is_copy_constructible_t<T>
istrue
.
constructs a new owned object with the owned object of other
as the argument
as an rvalue
and that only ever happens when alloc == other.alloc
is false.
It seems like we should require is_move_constructible_v
instead,
and only if the allocator traits mean we need to construct an object.
(Technically move-constructible might not be correct, because the allocator's
construct
member might use a different constructor).
Additionally, the noexcept-specifier for the move assignment doesn't match the effects. The noexcept-specifier says it can't throw if POCMA is true, but nothing in the effects says that ownership can be transferred in that case; we only do a non-throwing transfer when the allocators are equal. I think we should transfer ownership when POCMA is true, which would make the noexcept-specifier correct.
Proposed resolution:
This wording is relative to N5008.
Modify 20.4.1.5 [indirect.asgn] as indicated:
constexpr indirect& operator=(indirect&& other) noexcept(allocator_traits<Allocator>::propagate_on_container_move_assignment::value || allocator_traits<Allocator>::is_always_equal::value);
-5- Mandates: If
allocator_traits<Allocator>::propagate_on_container_move_assignment::value
isfalse
andallocator_traits<Allocator>::is_always_equal::value
isfalse
,is_
iscopymove_constructible_t<T>true
.-6- Effects: If
addressof(other) == this
istrue
, there are no effects. Otherwise:
- (6.1) — The allocator needs updating if
allocator_traits<Allocator>::propagate_on_container_move_assignment::value
istrue
.- (6.2) — If
other
is valueless,*this
becomes valuelessand the owned object in.*this
, if any, is destroyed usingallocator_traits<Allocator>::destroy
and then the storage is deallocated- (6.3) — Otherwise, if the allocator needs updating or if
alloc == other.alloc
istrue
,swaps the owned objects in*this
andother
; the owned object inother
, if any, is then destroyed usingallocator_traits<Allocator>::destroy
and then the storage is deallocated*this
takes ownership of the owned object ofother
.- (6.4) — Otherwise, constructs a new owned object with the owned object of
other
as the argument as an rvalue, using either the allocator in*this
or the allocator inother
if the allocator needs updating.- (6.5) — The previously owned object in
*this
, if any, is destroyed usingallocator_traits<Allocator>::destroy
and then the storage is deallocated.- (6.6) — If the allocator needs updating, the allocator in
*this
is replaced with a copy of the allocator inother
.-7- Postcondition:
other
is valueless.