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.