Title
uninitialized_copy appears to not be able to meet its exception-safety guarantee
Status
c++20
Section
[uninitialized.copy]
Submitter
Jon Cohen

Created on 2018-01-24.00:00:00 last changed 45 months ago

Messages

Date: 2018-11-12.04:39:29

Proposed resolution:

This wording is relative to N4713.

  1. Modify [specialized.algorithms] as indicated:

    -1- […]

    Unless otherwise specified, if an exception is thrown in the following algorithms objects constructed by a placement new-expression ([expr.new]) are destroyed in an unspecified order before allowing the exception to propagatethere are no effects.

  2. Modify [uninitialized.move] as indicated (The removed paragraphs are now unnecessary):

    template<class InputIterator, class ForwardIterator>
      ForwardIterator uninitialized_move(InputIterator first, InputIterator last,
                                         ForwardIterator result);
    

    […]

    -2- Remarks: If an exception is thrown, some objects in the range [first, last) are left in a valid but unspecified state.

    template<class InputIterator, class Size, class ForwardIterator>
      pair<InputIterator, ForwardIterator>
        uninitialized_move_n(InputIterator first, Size n, ForwardIterator result);
    

    […]

    -4- Remarks: If an exception is thrown, some objects in the range [first, std::next(first, n)) are left in a valid but unspecified state.

Date: 2018-11-12.04:39:29

[ 2018-11, Adopted in San Diego ]

Date: 2018-06-12.04:35:59

[ 2018-06 Rapperswil Thursday issues processing ]

Status to Ready

Date: 2018-02-15.00:00:00

[ 2018-02-05, Priority set to 2 after mailing list discussion ]

Date: 2018-01-15.00:00:00

[ 2018-01-24, Casey comments and provides wording ]

This issue points out a particular hole in the "..if an exception is thrown in the following algorithms there are no effects." wording for the "uninitialized" memory algorithms ([specialized.algorithms]/1) and suggests a PR to patch over said hole. The true problem here is that "no effects" is not and never has been implementable. For example, "first != last" may have observable effects that an implementation is required to somehow reverse if some later operation throws an exception.

Rather than finding problem case after problem case and applying individual patches, we should fix the root cause. If we alter the problematic sentence from [specialized.algorithms]/1 we can fix the issue once and for all and have implementable algorithms.

Date: 2018-01-24.21:05:33

I believe that uninitialized_copy is unable to meet its exception-safety guarantee in the presence of throwing move constructors:

[specialized.algorithms]/1 has two statements of note for the specialized algorithms such as uninitialized_copy:

  • the provided iterators satisfy the InputIterator requirements ([input.iterators])

  • if an exception is thrown during the algorithm then there are no effects

Suppose we have an input iterator Iter. Then std::move_iterator<Iter> appears to also be an input iterator. Notably, it still satisfies that (void)*a, *a is equivalent to *a for move iterator a since the dereference only forms an rvalue reference, it doesn't actually perform the move operation ([input.iterators] Table 95 — "Input iterator requirements").

Suppose also that we have a type T whose move constructor can throw, a range of T's [tbegin, tend), and a pointer to an uninitialized buffer of T's buf. Then std::uninitialized_copy(std::make_move_iterator(tbegin), std::make_move_iterator(tend), buf) can't possibly satisfy the property that it has no effects if one of the moves throws — we'll have a T left in a moved-from state with no way of recovering.

See here for an example in code.

It seems like the correct specification for uninitialized_copy should be that if InputIterator's operator* returns an rvalue reference and InputIterator::value_type's move constructor is not marked noexcept, then uninitialized_copy will leave the objects in the underlying range in a valid but unspecified state.

History
Date User Action Args
2021-02-25 10:48:01adminsetstatus: wp -> c++20
2018-11-12 04:39:29adminsetmessages: + msg10191
2018-11-12 04:39:29adminsetstatus: voting -> wp
2018-10-08 05:13:59adminsetstatus: ready -> voting
2018-06-12 04:35:59adminsetmessages: + msg9911
2018-06-12 04:35:59adminsetstatus: new -> ready
2018-02-08 18:38:38adminsetmessages: + msg9672
2018-01-25 18:32:50adminsetmessages: + msg9638
2018-01-25 18:32:50adminsetmessages: + msg9637
2018-01-24 00:00:00admincreate