This page is a snapshot from the LWG issues list, see theLibrary Active Issues List for more information and the meaning ofWP status.
std::uninitialized_move/_n and guaranteed copy elisionSection: 26.11.6[uninitialized.move]Status:WPSubmitter: Jiang AnOpened: 2023-04-04Last modified: 2024-11-28
Priority:3
View all issues withWP status.
Discussion:
Currentlystd::move is unconditionally used instd::uninitialized_move andstd::uninitialized_move_n, which may involve unnecessary move construction if dereferencing the input iterator yields a prvalue.
[2023-06-01; Reflector poll]
Set priority to 3 after reflector poll. Send to LEWG.
"P2283 wants to remove guaranteed elision here.""Poorly motivated, not clear anybody is using these algos with proxy iterators.""Consider usingiter_move in the move algos."
Previous resolution [SUPERSEDED]:
This wording is relative toN4944.
Modify 26.11.1[specialized.algorithms.general] as indicated:
-3- Some algorithms specified in 26.11[specialized.algorithms] make use of thefollowing exposition-only functions
:voidifytemplate<class T> constexpr void*voidify(T& obj) noexcept { return addressof(obj); }template<class I> decltype(auto)deref-move(const I& it) { if constexpr (is_lvalue_reference_v<decltype(*it)>) return std::move(*it); else return *it; }Modify 26.11.6[uninitialized.move] as indicated:
template<class InputIterator, class NoThrowForwardIterator> NoThrowForwardIterator uninitialized_move(InputIterator first, InputIterator last, NoThrowForwardIterator result);[…]-1-Preconditions:
-2-Effects: Equivalent to:result + [0, (last - first))does not overlap with[first, last).for (; first != last; (void)++result, ++first) ::new (voidify(*result)) typename iterator_traits<NoThrowForwardIterator>::value_type(std::move(*deref-move(first));return result;template<class InputIterator, class Size, class NoThrowForwardIterator> pair<InputIterator, NoThrowForwardIterator> uninitialized_move_n(InputIterator first, Size n, NoThrowForwardIterator result);-6-Preconditions:
-7-Effects: Equivalent to:result + [0, n)does not overlap withfirst + [0, n).for (; n > 0; ++result,(void) ++first, --n) ::new (voidify(*result)) typename iterator_traits<NoThrowForwardIterator>::value_type(std::move(*deref-move(first));return {first, result};
[2024-03-22; Tokyo: Jonathan updates wording after LEWG review]
LEWG agrees it would be good to do this.Usingiter_move was discussed, but it was noted that the versions of thesealgos in theranges namespace already use it and introducingranges::iter_move into the non-ranges versions wasn't desirable.It was observed that the proposedderef-move has aconst I& parameter which would be ill-formed for any iteratorwith a non-constoperator* member. Suggested removing the const andrecommended LWG to accept the proposed resolution.
Previous resolution [SUPERSEDED]:
This wording is relative toN4971.
Modify 26.11.1[specialized.algorithms.general] as indicated:
-3- Some algorithms specified in 26.11[specialized.algorithms] make use of thefollowing exposition-only functions
:voidifytemplate<class T> constexpr void*voidify(T& obj) noexcept { return addressof(obj); }template<class I> decltype(auto)deref-move(I& it) { if constexpr (is_lvalue_reference_v<decltype(*it)>) return std::move(*it); else return *it; }Modify 26.11.6[uninitialized.move] as indicated:
template<class InputIterator, class NoThrowForwardIterator> NoThrowForwardIterator uninitialized_move(InputIterator first, InputIterator last, NoThrowForwardIterator result);[…]-1-Preconditions:
-2-Effects: Equivalent to:result + [0, (last - first))does not overlap with[first, last).for (; first != last; (void)++result, ++first) ::new (voidify(*result)) typename iterator_traits<NoThrowForwardIterator>::value_type(std::move(*deref-move(first));return result;template<class InputIterator, class Size, class NoThrowForwardIterator> pair<InputIterator, NoThrowForwardIterator> uninitialized_move_n(InputIterator first, Size n, NoThrowForwardIterator result);-6-Preconditions:
-7-Effects: Equivalent to:result + [0, n)does not overlap withfirst + [0, n).for (; n > 0; ++result,(void) ++first, --n) ::new (voidify(*result)) typename iterator_traits<NoThrowForwardIterator>::value_type(std::move(*deref-move(first));return {first, result};
[St. Louis 2024-06-24; revert P/R and move to Ready]
Tim observed that the iterator requirements require all iterators to beconst-dereferenceable, so there was no reason to remove the const.Restore the original resolution and move to Ready.
[Wrocław 2024-11-23; Status changed: Voting → WP.]
Proposed resolution:
This wording is relative toN4971.
Modify 26.11.1[specialized.algorithms.general] as indicated:
-3- Some algorithms specified in 26.11[specialized.algorithms] make use of thefollowing exposition-only functions
:voidifytemplate<class T> constexpr void*voidify(T& obj) noexcept { return addressof(obj); }template<class I> decltype(auto)deref-move(I& it) { if constexpr (is_lvalue_reference_v<decltype(*it)>) return std::move(*it); else return *it; }
Modify 26.11.6[uninitialized.move] as indicated:
template<class InputIterator, class NoThrowForwardIterator> NoThrowForwardIterator uninitialized_move(InputIterator first, InputIterator last, NoThrowForwardIterator result);[…]-1-Preconditions:
-2-Effects: Equivalent to:result + [0, (last - first))does not overlap with[first, last).for (; first != last; (void)++result, ++first) ::new (voidify(*result)) typename iterator_traits<NoThrowForwardIterator>::value_type(std::move(*deref-move(first));return result;template<class InputIterator, class Size, class NoThrowForwardIterator> pair<InputIterator, NoThrowForwardIterator> uninitialized_move_n(InputIterator first, Size n, NoThrowForwardIterator result);-6-Preconditions:
-7-Effects: Equivalent to:result + [0, n)does not overlap withfirst + [0, n).for (; n > 0; ++result,(void) ++first, --n) ::new (voidify(*result)) typename iterator_traits<NoThrowForwardIterator>::value_type(std::move(*deref-move(first));return {first, result};