https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127540

Harald van Dijk <harald at gigawatt dot nl> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |harald at gigawatt dot nl

--- Comment #2 from Harald van Dijk <harald at gigawatt dot nl> ---
Swapping internally does an assignment from the moved-from i, and the error
also shows up when doing that directly, or likewise with construction rather
than assignment:

#define _GLIBCXX_DEBUG
#include <vector>
int main() {
  std::vector<int> v;
  std::vector<int>::iterator a = v.begin();
  std::vector<int>::iterator b = std::move(a);
  std::vector<int>::iterator c = std::move(a);
}

The standard allows this behaviour of iterators in general: it says "holds a
singular value" a valid state of iterators and that it's undefined behaviour to
use such a value as a source of copy/move construction or assignment
(https://eel.is/c++draft/iterator.requirements#general-7), and it says that a
moved-from object is placed in an unspecified but valid state
(https://eel.is/c++draft/lib.types.movedfrom) which therefore could be holding
a singular value.

However, it also requires the library's iterator types to meet additional
guarantees:

https://eel.is/c++draft/vector

A vector meets all of the requirements of a container ([container.reqmts])
[...]

https://eel.is/c++draft/container.reqmts

typename X::iterator
Result: A type that meets the forward iterator requirements
([forward.iterators]) with value type T. [...]

https://eel.is/c++draft/forward.iterators

A class or pointer type X meets the Cpp17ForwardIterator requirements if
 -- X meets the Cpp17InputIterator requirements ([input.iterators]),

https://eel.is/c++draft/input.iterators

A class or pointer type X meets the requirements of an input iterator for the
value type T if X meets the Cpp17Iterator ([iterator.iterators]) and [...]

https://eel.is/c++draft/iterator.iterators

A type X meets the Cpp17Iterator requirements if
 -- X meets the Cpp17CopyConstructible, Cpp17CopyAssignable, Cpp17Swappable,
and Cpp17Destructible requirements ([utility.arg.requirements],
[swappable.requirements]), and [...]

https://eel.is/c++draft/utility.arg.requirements

There are no preconditions here on the source of copy or move construction or
assignment, so an iterator that places additional preconditions does not meet
those requirements.

This means, I think, that the assertion as it is currently implemented is just
not valid. What I think the assertion aims to protect against is

#include <vector>
int main() {
  std::vector<int>::iterator a, b; // valid
  a = b; // undefined behaviour
}

However, due to the way it is implemented, this case is not caught by the
assertion anyway because the type has no way to distinguish between default
initialisation and value initialisation.

I believe the right fix is to just remove the assertion entirely.

Reply via email to