Reputation: 635
Does the standard guarantee that
--list.begin() == list.end()
always holds and that it infact is a valid operation? (list
is an instance of std::list
).
It appears to be the case with at least MSVC 2019.
This would be useful for instance in the following case:
for ( auto i = list.begin(); i != list.end(); ++i )
{
...
list.erase(i--);
...
}
, i.e. when deleting elements while iterating, since i
may be the beginning of the list. This would also require ++list.end() == list.begin()
to hold; what about that?
Upvotes: 0
Views: 766
Reputation: 238351
Does the standard guarantee that
--list.begin() == list.end()
No, standard does not guarantee that for std::list
(nor can such guarantee be assumed given a bidirectional iterator). In fact, the behaviour of --list.begin()
is undefined.
This would also require ++list.end() == list.begin() to hold; what about that?
Also not guaranteed, and ++list.end()
has undefined behaviour.
Standard quote for [language-lawyer]:
[bidirectional.iterators]
Expression | Operational | Assertion/note | semantics | pre-/post-condition --------------------------------------------------------- --r | | Preconditions: | | there exists s such that r == ++s. --------------------------------------------------------- r-- | { X tmp = r; | | --r; | | return tmp; } |
[input.iterators]
Expression | Operational | Assertion/note | semantics | pre-/post-condition --------------------------------------------------------- ++r | | Preconditions: | | r is dereferenceable.
Problem is that the pre-condition is not satisfied.
My suggestion for writing the concrete example. This is slightly different in that my_function
will be called before elements are actually removed from the list:
list.remove_if([](int n) {
if ( X + Y == W )
{
my_function( Y );
return X || Y && Z;
}
return true;
});
If the exact behaviour is needed, then you can use following which isn't quite as pretty:
for (auto it = list.begin(), last = list.end(); it != last;)
{
auto next = it;
++next;
if ( X + Y == W )
{
if ( X || Y && Z )
{
list.erase( it );
}
my_function( Y );
}
else
{
list.erase( it );
}
it = next;
}
Upvotes: 8
Reputation: 234715
The current MSVC C++ standard library implements std::list
as a circular doubly linked list, with an extra node acting as a coupler between the first and last element.
So --list.begin() == list.end()
does hold true.
But note that the behaviour of --list.begin()
is undefined, which is why this particular implementation is a possible choice.
Upvotes: 3