This question already has answers here:
How to call erase with a reverse iterator
(13 answers)
Closed 3 years ago.
The community reviewed whether to reopen this question 6 months ago and left it closed:
Original close reason(s) were not resolved
I'm trying to solve a problem in C++, a part of which requires me to erase elements from a vector using the rbegin() member function. However, the compiler throws an error every time I write the below-mentioned code. What's wrong here?
int main() {
int a = 1, b = 2;
vector<int> V = {a, b};
auto it = V.rbegin();
V.erase(it);
return 0;
}
It compiles just fine, however, if I access the same element using the begin() member function. The code below works fine.
int main() {
int a = 1, b = 2;
vector<int> V = {a, b};
auto it = V.begin()+1;
V.erase(it);
return 0;
}
There is no std::vector::erase() overload for reverse_iterator. However, you can obtain the corresponding iterator from a reverse_iterator by calling its base() member function:
auto rit = V.rbegin();
auto it = rit.base();
V.erase(it);
This code does compile but results in undefined behavior because the iterator counterpart of rbegin() corresponds to end(). From std::vector::erase() documentation:
iterator erase(const_iterator pos);
The iterator pos must be valid and dereferenceable. Thus the end() iterator (which is valid, but is not dereferencable) cannot be used as a value for pos.
rbegin().base() returns end(), not end() - 1. Nevertheless, you can advance rbegin() by one if you want a dereferencable iterator:
auto it = (std::next(rit)).base();
Related
This question already has answers here:
map.erase( map.end() )?
(4 answers)
Closed 2 years ago.
int main(){
map<int, int> m;
m.insert({1,2});
m.insert({2,3});
m.insert({5,10});
m.erase(m.find(3));
for(auto &x: m){
cout<<x.first<<" "<<x.second<<nl;
}
}
Output:
1 2
5 10
As far as I know m.find(3) returns iterator to the m.end() if key is not found. Then why pair {2,3} is deleted?
The pair is deleted because you violated a pre-condition of std::map::erase
iterator erase( const_iterator pos );
iterator erase( iterator pos );
The iterator pos must be valid and dereferenceable. Thus the end()
iterator (which is valid, but is not dereferenceable) cannot be used
as a value for pos.
Violating a pre-condition of a standard library function has undefined behavior. So deleting a seemingly random element is totally in line with that.
This question already has answers here:
Iterator invalidation rules for C++ containers
(6 answers)
Closed 3 years ago.
I cannot figure why I'm getting an error when running the following simple program
#include <iostream>
#include <vector>
int main(int argc, char** argv) {
std::vector<int> v{ 1,2,3,4,5 };
std::vector<int>::iterator it1 = v.end();
auto it_tmp = v.insert(v.end(), 6);
std::vector<int>::iterator it2 = v.end();
std::cout << (it1 == it2) << std::endl;
return 0;
}
The iterators it1 and it2 are incompatible, so I was wondering what could possible be the issue. Iterators are incompatible if they belong to different containers, I would then assume in my case one of the two gets invalidated or something like that (I've also try to change v.end with v.begin() for both it1 and it2, it doesn't make any difference).
Thank you.
it1 == it2 evaluates false because after this auto it_tmp = v.insert(v.end(), 6);, end iterator changes.
std::vector::insert inserts before the given iterator. Everything before the insertion point remains valid. Everything after it is invalidated. it1 here is invalidated:
std::vector::insert
Causes reallocation if the new size() is greater than the old
capacity(). If the new size() is greater than capacity(), all
iterators and references are invalidated. Otherwise, only the
iterators and references before the insertion point remain valid. The
past-the-end iterator is also invalidated.
This question already has answers here:
Get a reverse iterator from a forward iterator without knowing the value type
(2 answers)
Closed 6 years ago.
I find a certain point in an std::map<int, X> via upper_bound and then from this point on I iterate backwards. My code looks something like:
MAP::reverse_iterator iter;
iter = _map.upper_bound(value); // Does not compile because upper_bound is not reverse_iterator
while(iter != rbegin()){
// logic
--iter;
}
I get a compile error because upper_bound() does not return a reverse_iterator.
What is the best approach to remedy this?
You need to convert your iterator to a reverse iterator:
auto iter = _map.upper_bound(value);
for (std::reverse_iterator<decltype(iter)> rit{iter}; rit != _map.rend(); ++rit) {
// Do whatever you want...
}
Note that you have to stop when reaching _map.rend(), not _map.rbegin(), and you need to increment the reverse iterator, not decrement it.
This question already has an answer here:
Substraction or decrement random access iterator pointing to begin
(1 answer)
Closed 9 years ago.
What should std::map iterator decrement return, if there's only single element in the map? Here's the sample code
#include <map>
#include <stdio.h>
int main()
{
std::map<int, int> m;
m.insert(std::make_pair(1, 1));
//std::map<int, int>::iterator it = m.begin();
std::map<int, int>::iterator it = m.upper_bound(0);
printf("isbegin: %d\n", it == m.begin());
--it;
bool isend = it == m.end();
printf("isend: %d\n", isend);
}
On Windows it will print isend: 1, on Linux with g++ 4.6 it will print isend: 0.
The question: is the decrement above really a case of UB? and if not then what result is correct - Windows or Linux one?
UPDATE: modified code to show that upper_bound is called
Decrementing something to the element before begin() doesn't make sense. This is undefined behavior and there is no correct or incorrect answer.
for an iterator r the operation --r is valid if before the operation is done there exists s such that r == ++s and after the operation is done r is dereferenceable. (§24.2.6 Bidirectional.iterators )
Since begin() returns an iterator to the first element of the container there is no element s which can be incremented to get to r so this is undefined.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
iterator validity ,after erase() call in std::set
When I iterate over a set and want to delete certain items the iterators are changed. This results in segfaults as the iteration fails after deletion. How can I overcome this problem?
std::set< std::pair<double,unsigned>, comparisonFunction> candidates;'
[...]
for( auto it = candidates.begin(); it != candidates.end(); ++it)
{
[...]
if ( some constraint satisfied)
{
candidates.erase(it);
}
}
I encounter a segfault when I use this code. My guess is that this is either due to the corrupted iterators or due to the fact, that the element to be deleted is the last element in some cases. Does a post increment on the iterator overcome this problem? Like this:
candidate.erase(it++);
Use the return value of erase:
it = candidates.erase(it);
Note that you must not increment it if you erase an element, otherwise your iterator could be invalidated.
for( auto it = candidates.begin(); it != candidates.end();)
{
if ( some constraint satisfied)
{
it = candidates.erase(it);
}
else
++it;
}
Also note that this wasn't possible in C++03, since erase didn't return any iterator. However, since you're using C++11 it shouldn't be a problem.
References
std::set::erase