13

During the proceedings of this question, it came to light that there appear to be no time complexity requirements placed on std::vector<T>::clear by the C++ standard.

Table 100 under 23.2.3 says:

Destroys all elements in a. Invalidates all references, pointers, and iterators referring to the elements of a and may invalidate the past-the-end iterator. post: a.empty() returns true

And... that's it. There's no entry for it specifically under 23.3.6, and no explicit indication that the following applies to clear:

[C++11: 23.3.6.1/1]: A vector is a sequence container that supports random access iterators. In addition, it supports (amortized) constant time insert and erase operations at the end; insert and erase in the middle take linear time. Storage management is handled automatically, though hints can be given to improve efficiency. [..]

So... is this really true? Or have I simply missed it?

Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055

1 Answers1

16

This seems to be an unintended consequence of DR 704 (and the related DR 1301) which removed the wording saying clear() was equivalent to erase(begin(), end()) because erase() requires MoveAssignable, which isn't needed when erasing every element. Removing the definition in terms of erase() also removes the complexity requirement. That can probably be handled editorially; I've raised it with the committee.

N.B. std::deque::clear() and std::forward_list::clear() are also affected. std::list::clear() does have a complexity guarantee.

Edit: this is now http://cplusplus.github.com/LWG/lwg-active.html#2231

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • Erasing a trailing subset shouldn't require `MoveConstructible` either. And what about `resize(0)`? Perhaps it would be better to make `clear()` equivalent to `resize(0)`, thus getting `resize`'s complexity requirement. – Ben Voigt Dec 30 '12 at 22:40
  • Most sequences don't have `resize()`. Requirements on types (i.e. required concepts) are not specified in terms of values, but in terms of types. Concept-checking for `erase(i, j)` requires MoveAssignable (not MoveConstructible as I originally wrote, sorry), even if no moves will take place for the specific values `i` and `j`. – Jonathan Wakely Dec 30 '12 at 22:47
  • 1
    Hmmm. It seems like there needs to be another operation (`truncate` perhaps) then, for erasure from specified iterator to the end. Typically `erase(it, end()` is used for this, but a new operation wouldn't require `MoveAssignable` as `erase` does. – Ben Voigt Dec 30 '12 at 23:08
  • 2
    The sequence containers that require MoveAssignable for `erase()`, `vector` and `deque`, already provide `pop_back()` and `resize()` which meet that need. I don't think there's a current problem that would be solved by adding `truncate()`, the problem was that `clear()` was inappropriately defined in terms of `erase()` not that there is no way to clear non-MoveAssignable elements from the end of a sequence. The problem was one of a poor choice of wording in the standard, not missing functionality. – Jonathan Wakely Dec 30 '12 at 23:18