#include <string>
#include <iostream>
int main() {
std::string s = "abcdef";
std::string s2 = s;
auto begin = const_cast<std::string const &>(s2).begin();
auto end = s2.end();
std::cout << end - begin << '\n';
}
This code mixes the result of begin() const
with the result of end()
. Neither of these functions is permitted to invalidate any iterators. However I'm curious whether the requirement of end()
to not invalidate the iterator variable begin
actually means that the variable begin
is usable with end
.
Consider a C++98, copy-on-write implementation of std::string
; the non-const begin()
and end()
functions cause a the internal buffer to be copied because the result of these functions can be used to modify the string. So begin
above starts out valid for both s
and s2
, but the use of the non-const end()
member causes it to no longer be valid for s2
, the container that produced it.
The above code produces 'unexpected' results with a copy-on-write implementation, such as libstdc++. Instead of end - begin
being the same as s2.size()
, libstdc++ produces another number.
Does causing
begin
to no longer be valid iterator intos2
, the container it was retrieved from, constitute 'invalidating' the iterator? If you look at the requirements on iterators, they all appear to hold for this iterator after.end()
is called, so perhapsbegin
still qualifies as a valid iterator, and thus has not been invalidated?Is the above code well defined in C++98? In C++11, which prohibits copy-on-write implementations?
From my own brief reading of the specs, it appears under-specified, so that there may not be any guarantee that the results of begin()
and end()
can ever be used together, even without mixing const and non-const versions.