Title
`inplace_vector` insertion functions do not specify iterator invalidation
Status
new
Section
[inplace.vector.modifiers]
Submitter
Karolis Špukas

Created on 2026-10-06.00:00:00 last changed 7 days ago

Messages

Date: 2026-10-10.13:28:59

Proposed resolution:

This wording is relative to N5054.

  1. Modify [inplace.vector.modifiers] as indicated:

    constexpr iterator insert(const_iterator position, const T& x);
    constexpr iterator insert(const_iterator position, T&& x);
    […]
    template<class... Args>
      constexpr iterator emplace(const_iterator position, Args&&... args);
    template<container-compatible-range <T> R>
      constexpr void append_range(R&& rg);
    

    -1- Let `n` be the value of `size()` before this call for the `append_range` overload, and `distance(begin, position)` otherwise.

    -2- Complexity: Linear in the number of elements inserted plus the distance to the end of the vector.

    -3- Remarks: References, pointers, and iterators before the insertion point remain valid, but those at or after the insertion point, including the past-the-end iterator, are invalidated. If an exception is thrown other than by the copy constructor, move constructor, assignment operator, or move assignment operator of `T` or by any `InputIterator` operation, there are no effects. Otherwise, if an exception is thrown, then size() ≥ n and elements in the range `begin() + [0, n)` are not modified.

    constexpr reference push_back(const T& x);
    constexpr reference push_back(T&& x);
    template<class... Args>
      constexpr reference emplace_back(Args&&... args);
    

    -4- Returns: `back()`.

    -5- Throws: `bad_alloc` or any exception thrown by the initialization of the inserted element.

    -6- Complexity: Constant.

    -7- Remarks: If an element is appended, invalidates the past-the-end iterator. If an exception is thrown, there are no effects on `*this`.

    template<class... Args>
      constexpr optional<reference> try_emplace_back(Args&&... args);
    constexpr optional<reference> try_push_back(const T& x);
    constexpr optional<reference> try_push_back(T&& x);
    

    -8- Let `vals` denote a pack: […]

    -9- Preconditions: […]

    -10- Effects: If size() < capacity() is `true`, appends an object of type `T` direct-non-list-initialized with `vals...`. Otherwise, there are no effects.

    -11- Returns: `nullopt` if `size() == capacity()` is `true`, otherwise optional<reference>(in_place, back()).

    -12- Throws: Nothing unless an exception is thrown by the initialization of the inserted element.

    -13- Complexity: Constant.

    -14- Remarks: If an element is appended, invalidates the past-the-end iterator. If an exception is thrown, there are no effects on `*this`.

Date: 2026-10-06.00:00:00

[inplace.vector.modifiers] does not specify iterator and reference invalidation for insertion functions.

According to [container.reqmts] p67, the current wording of [inplace.vector.modifiers] implies that `inplace_vector` insertions do not invalidate iterators and references or change the values of objects in the container:

Unless otherwise specified (either explicitly or by defining a function in terms of other functions), invoking a container member function or passing a container as an argument to a library function shall not invalidate iterators to, or change the values of, objects within that container.

P0843R8 specified reference invalidation for `insert` and `emplace`, for example:

constexpr iterator insert(const_iterator position, value_type&& x);

Effects: Inserts `x` at position and invalidates all references to elements after position.

This wording was removed in P0843R9 with no corresponding changelog entry.

On the other hand, [inplace.vector.modifiers] p19 still specifies invalidation for erasure:

Effects: Invalidates iterators and references at or after the point of the erase.

For comparison, [vector.modifiers]/2 specifies invalidation for insertion without reallocation:

If no reallocation happens, then references, pointers, and iterators before the insertion point remain valid but those at or after the insertion point, including the past-the-end iterator, are invalidated.

I took a quick look at libstdc++ implementation. I believe an insertion to `inplace_vector` can shift elements, therefore it is inconsistent with [container.reqmts] p67.

History
Date User Action Args
2026-10-10 13:28:59adminsetmessages: + msg16630
2026-10-06 00:00:00admincreate