This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++11 status.

149. Insert should return iterator to first element inserted

Section: 23.2.4 [sequence.reqmts] Status: C++11 Submitter: Andrew Koenig Opened: 1999-06-28 Last modified: 2016-11-12

Priority: Not Prioritized

View other active issues in [sequence.reqmts].

View all other issues in [sequence.reqmts].

View all issues with C++11 status.

Discussion:

Suppose that c and c1 are sequential containers and i is an iterator that refers to an element of c. Then I can insert a copy of c1's elements into c ahead of element i by executing

c.insert(i, c1.begin(), c1.end());

If c is a vector, it is fairly easy for me to find out where the newly inserted elements are, even though i is now invalid:

size_t i_loc = i - c.begin();
c.insert(i, c1.begin(), c1.end());

and now the first inserted element is at c.begin()+i_loc and one past the last is at c.begin()+i_loc+c1.size().

But what if c is a list? I can still find the location of one past the last inserted element, because i is still valid. To find the location of the first inserted element, though, I must execute something like

for (size_t n = c1.size(); n; --n)
   --i;

because i is now no longer a random-access iterator.

Alternatively, I might write something like

bool first = i == c.begin();
list<T>::iterator j = i;
if (!first) --j;
c.insert(i, c1.begin(), c1.end());
if (first)
   j = c.begin();
else
   ++j;

which, although wretched, requires less overhead.

But I think the right solution is to change the definition of insert so that instead of returning void, it returns an iterator that refers to the first element inserted, if any, and otherwise is a copy of its first argument. 

[ Summit: ]

Reopened by Alisdair.

[ Post Summit Alisdair adds: ]

In addition to the original rationale for C++03, this change also gives a consistent interface for all container insert operations i.e. they all return an iterator to the (first) inserted item.

Proposed wording provided.

[ 2009-07 Frankfurt ]

Q: why isn't this change also proposed for associative containers?

A: The returned iterator wouldn't necessarily point to a contiguous range.

Moved to Ready.

Proposed resolution:

23.2.4 [sequence.reqmts] Table 83 change return type from void to iterator for the following rows:

Table 83 — Sequence container requirements (in addition to container)
Expression Return type Assertion/note pre-/post-condition
a.insert(p,n,t) void iterator Inserts n copies of t before p.
a.insert(p,i,j) void iterator Each iterator in the range [i,j) shall be dereferenced exactly once. pre: i and j are not iterators into a. Inserts copies of elements in [i, j) before p
a.insert(p,il) void iterator a.insert(p, il.begin(), il.end()).

Add after p6 23.2.4 [sequence.reqmts]:

-6- ...

The iterator returned from a.insert(p,n,t) points to the copy of the first element inserted into a, or p if n == 0.

The iterator returned from a.insert(p,i,j) points to the copy of the first element inserted into a, or p if i == j.

The iterator returned from a.insert(p,il) points to the copy of the first element inserted into a, or p if il is empty.

p2 23.3.5 [deque] Update class definition, change return type from void to iterator:

void iterator insert(const_iterator position, size_type n, const T& x);
template <class InputIterator>
  void iterator insert(const_iterator position, InputIterator first, InputIterator last);
  void iterator insert(const_iterator position, initializer_list<T>);

23.3.5.4 [deque.modifiers] change return type from void to iterator on following declarations:

  void iterator insert(const_iterator position, size_type n, const T& x);
template <class InputIterator>
  void iterator insert(const_iterator position, InputIterator first, InputIterator last);

Add the following (missing) declaration

iterator insert(const_iterator position, initializer_list<T>);

[forwardlist] Update class definition, change return type from void to iterator:

void iterator insert_after(const_iterator position, initializer_list<T> il);
void iterator insert_after(const_iterator position, size_type n, const T& x);
template <class InputIterator>
  void iterator insert_after(const_iterator position, InputIterator first, InputIterator last);

p8 [forwardlist.modifiers] change return type from void to iterator:

void iterator insert_after(const_iterator position, size_type n, const T& x);

Add paragraph:

Returns: position.

p10 [forwardlist.modifiers] change return type from void to iterator:

template <class InputIterator>
  void iterator insert_after(const_iterator position, InputIterator first, InputIterator last);

Add paragraph:

Returns: position.

p12 [forwardlist.modifiers] change return type from void to iterator on following declarations:

void iterator insert_after(const_iterator position, initializer_list<T> il);

change return type from void to iterator on following declarations:

p2 23.3.9 [list] Update class definition, change return type from void to iterator:

void iterator insert(const_iterator position, size_type n, const T& x);

template <class InputIterator>
void iterator insert(const_iterator position, InputIterator first, InputIterator last);

void iterator insert(const_iterator position, initializer_list<T>);

23.3.9.4 [list.modifiers] change return type from void to iterator on following declarations:

void iterator insert(const_iterator position, size_type n, const T& x);

template <class InputIterator>
  void iterator insert(const_iterator position, InputIterator first, InputIterator last);

Add the following (missing) declaration

iterator insert(const_iterator position, initializer_list<T>);

p2 23.3.11 [vector]

Update class definition, change return type from void to iterator:

void iterator insert(const_iterator position, T&& x);

void iterator insert(const_iterator position, size_type n, const T& x);

template <class InputIterator>
  void iterator insert(const_iterator position, InputIterator first, InputIterator last);

void iterator insert(const_iterator position, initializer_list<T>);

23.3.11.5 [vector.modifiers] change return type from void to iterator on following declarations:

void iterator insert(const_iterator position, size_type n, const T& x);

template <class InputIterator>
  void iterator insert(const_iterator position, InputIterator first, InputIterator last);

Add the following (missing) declaration

iterator insert(const_iterator position, initializer_list<T>);

p1 23.3.12 [vector.bool] Update class definition, change return type from void to iterator:

void iterator insert (const_iterator position, size_type n, const bool& x);

template <class InputIterator>
  void iterator insert(const_iterator position, InputIterator first, InputIterator last);

  void iterator insert(const_iterator position, initializer_list<bool> il);

p5 27.4.3 [basic.string] Update class definition, change return type from void to iterator:

void iterator insert(const_iterator p, size_type n, charT c);

template<class InputIterator>
  void iterator insert(const_iterator p, InputIterator first, InputIterator last);

void iterator insert(const_iterator p, initializer_list<charT>);

p13 27.4.3.7.4 [string.insert] change return type from void to iterator:

void iterator insert(const_iterator p, size_type n, charT c);

Add paragraph:

Returns: an iterator which refers to the copy of the first inserted character, or p if n == 0.

p15 27.4.3.7.4 [string.insert] change return type from void to iterator:

template<class InputIterator>
  void iterator insert(const_iterator p, InputIterator first, InputIterator last);

Add paragraph:

Returns: an iterator which refers to the copy of the first inserted character, or p if first == last.

p17 27.4.3.7.4 [string.insert] change return type from void to iterator:

void iterator insert(const_iterator p, initializer_list<charT> il);

Add paragraph:

Returns: an iterator which refers to the copy of the first inserted character, or p if il is empty.

Rationale:

[ The following was the C++98/03 rationale and does not necessarily apply to the proposed resolution in the C++0X time frame: ]

The LWG believes this was an intentional design decision and so is not a defect. It may be worth revisiting for the next standard.