C++ Vector.erase() causing segmentation fault - c++

I have a C++ vector and it has some blank elements in it. I wanted to remove any empty string elements from the vector. I tried this code:
for (i = 0; i < myvector.size();i++) {
if (myvector[i] == "") {
myvector.erase(myvector.begin()+i);
}
}
When I run this code I get a segmentation fault. Is there something wrong with it? Or does this code work for any of you?

It appears that you want the usual remove-erase idiom:
#include <algorithm>
#include <functional>
myvector.erase(std::remove_if(myvector.begin(), myvector.end(),
std::mem_fn(&std::string::empty)),
myvector.end());

If you have for example vec=["A","","B","C"] and you're delete the element a[1], now 'vec' is long 3 not 4, so vec[3] causes segmentation fault.
Try this:
for (vector<...>::iterator i=myvector.begin();
i != myvector.end(); /* do nothing here */) {
if (i->empty()) {
i=myvector.erase(i);
} else {
++i;
}
}
However Kerrek's solution is more elegant.

First of all, I'm sorry for my English (I'm Brazilian and I'm using the Google translator). But your problem is not exclusively about deleting an item outside the vector, but about accessing its element. Think about the following situation: I have a vector v = {1, 4, 2} and I want to exclude all even numbers using a for and an iterator. When the iterator arrives at the second element (v [2]) it will exclude 4, making the vector {1,2}. But before leaving the for loop, the iterator is still pointing to the second element (v [2]), which is the last element. When it exits, the iterator will be incremented (i ++) and will be equal to v.end (). Therefore, even if it does not give a segmentation fault, the algorithm will not remove all even numbers and, if v was equal to {1,3,4}, it would give the segmentation fault. To fix this, right when you use v.erase (), use i-- (which in the case of your code, which does not directly use the iterator, will work in the same way).Or you can use an increment condition, as in the previous answer, but the iterator needs to be updated correctly.

Related

Why don't elements from my list get erased

I have to write a function that erases an element out of the list if it's bigger than the previous element.(The previous element is the one which points to the next element before deletion)
I think I've basically finished it but I don't know why it doesn't erase 5 out of my list.
void deleteBigger(list<int> s){
list<int>::iterator test;
for(test = s.begin(); test != s.end(); test++){
int sk1=*test;
cout<<sk1<<endl;
test--;
int sk2=*test;
cout<<sk2<<endl;
if(sk1>sk2){
cout<<"Im here!\n";
s.erase(test);
}
test++;
}
}
It doesn't give an error or anything it just doesn't erase. I tried to test the erase method in the main function of the program, and there it worked fine.
There are three problems with your code:
Your list is passed by value, not reference. So you are changing a copy of your list and it doesn't alter the original container
You try to remove an element from a list while iterating it. Edit: As #Remy Lebeau mentioned in the comments, to be more precise it's a problem because you don't update the iterator properly, but not a problem on its own. Be advised, that when you remove an element from a list, the iterator which pointed to the erased element is considered invalidated.
Upon the first iteration, you decremented the iterator out of the container's bounds
Summing it up, what you might want to have here looks something like this:
void deleteBigger(std::list<int> &s) {
using namespace std;
if (s.empty()) {
return;
}
for(auto test = next(s.cbegin()); test != s.cend(); ++test){
while ((*test > *prev(test)) && (test != s.cend())) {
test = s.erase(test);
}
}
}
I've copied your code and it doesn't work. The problem is your iterator pointer "test". You can't degree a pointer at the begin. The only thing you can do is use a control.
Note: it's wrong decrement a pointer because you are decrementing of (32 bits) the index of memory. In this case there is overriding -- operator that saves your program but be careful next times
Control your program. It's important use a debugger editor where you can stop the program at certain point and control the value of the variables

C++ Vectors not performing as intuitively as I thought

I've been trying to learn how to use vectors in c++, and they seem much more complicated in java. In order to add items to a vector, I've had to use an iterator. What I'd like to be able to do is just use add remove functions and loop over them as in java. Is this possible? I'm trying to achieve something like the line I marked with an error below : insert(index 3, number 13), but this throws an error. Thanks in advance.
vector<int> myvector(0,0);
vector<int>::iterator it;
it = myvector.begin();
int q = 0;
for(it=myvector.begin();q<16;q++){
it = myvector.insert (it, q);
}
myvector.insert(3,13); //ERROR
You got advice above how to populate the vector.
If you want to insert something at specific index, you can do the following
//similar to myvector.insert(3,13); //ERROR
myvector.insert( myvector.begin()+3, 13);
The code above will insert 13 before element #3 so that 13 becomes element #3 (numeration starts with 0, so "begin" corresponds to element #0).
To replace element #3 with 13, you simply use
myvector[3] = 13;
Here is the link where you can learn about the C++ STL(Standard Template Library), such as: vector, queue, stack, list etc.

How to find the second to last element in a vector in C++?

I am trying to build a program that uses the second to last element in a vector, so far I've used:
(arr2.rbegin()+1)
If I use a comparison operator in a conditional such as:
if(arr2.rbegin()+1 == true)
I get an error message: no match for operator ==
Many of the answers and comments have the right idea but really ugly syntax. Here are two nice ways to express that.
arr2.end()[-2] // end() is past the last element, -1 for last element, -2 for second-last
arr2.rbegin()[1] // rbegin() is reverse order starting at 0 for last element, 1 for second-last
Demo: http://ideone.com/2cZeUq
It works because RandomAccessIterator, which vector has, is required to provide operator[] such that it[n] is equivalent to *(it + n), just like for pointers.
So the code in your question becomes just
if (arr2.rbegin()[1]) // test penultimate element
looking at the documentation here
http://www.cplusplus.com/reference/vector/vector/?kw=vector
I'd expect you to access your element by
secondToLast = myVector[myVector.size() - 2];
You can try doing like this:-
if(*(arr2.rbegin()+1))
Sometimes there might be less than 2 items in the list, so myVector.size() - 2 or other direct accessors will throw an error. I've done the following . . .
if (myVector.size() > 1)
{
secondToLast = myVector[myVector.size() - 2];
}
It depends on what you mean by "second to last element". Take the following iterator definition...
vector<int>::iterator it = arr2.end();
it--;
it--;
You have to decriment the iterator twice because when you declare the iterator to "point" to the end, it actually references the location AFTER the last element in the vector.
Dont forget that when you want the value that the iterator points to, you have to dereference it. like so...
cout << *it;
Mostly for lulz, but if your elements are non-scalar and you need to access a member of the element in question, you can use the ++-> construction:
std::vector<std::pair<int, int>> arr = ...;
auto grug = arr.rbegin()[1].first;
auto leet = arr.rbegin()++->first;
assert(grug == leet);
The way it works is we post-increment the iterator returned by rbegin() with ++ and then access it with ->. It is actually superior to the clearest [1] form in the sense it will work on any iterator, not only random access iterator.
Post it on review and get some popcorn.
There are many ways you can access elements from the back
one you can use is the back property that comes with std::vector container
and if you want to access an element from the back (either last element or up to n)
you can do this
std::vector vec{1,2,3};
int lastsecond = vec.back()-1; will give you -> 2;
you can check vector properties which there is a decent bit.
https://en.cppreference.com/w/cpp/container/vector

Valid or Invalid Iterators And Iterator Positions

I have a simple example routine below for erasing vector elements, the positions of which are stored in another vector. I've been using this method for some time now and only recently have experienced an error: Expression: vector iterator + offset out of range.
I seem to have found the problem, that being within the parameters of the erase() call I wasn't enclosing the 2nd part in parenthesis, which occasionally resulted in the above error when erasing elements near the end of the vector.
Now I've identified and corrected the problem, I would be grateful if somebody could just confirm that my simple routine below is in fact valid and without error, and that to call erase() within a for-loop in this way is okay.
I realise this routine only works if erasing element positions in order of first to last. Please see my code below:
vector<int> mynumbers;
mynumbers.push_back(4);
mynumbers.push_back(5);
mynumbers.push_back(6);
mynumbers.push_back(7);
vector<int> delpositions;
delpositions.push_back(1);
delpositions.push_back(2);
delpositions.push_back(3);
for(unsigned int i = 0; i < delpositions.size(); ++i)
mynumbers.erase(mynumbers.begin() + (delpositions[i] - i));
// Used To Be: delpositions[i] - i Which Caused The Error! Instead of: (delpositions[i] - i)
You do the right thing by adjusting the 'delposition' by the number of elements erased. Just ensure 'delpositions' are sorted ascending.
Erasing in reverse order (last to first) might be a bit more efficient.
I consider
vector result;
result.reserve(mynumbers.size() - delpositions.size());
// copy valid positions to result
mynumbers.swap(result)
a better solution

Vector gets iterated more times than size()

I've got this piece of code:
for (std::vector<Marker>::iterator it = markers.begin(); it != markers.end(); ++it) {
if (it->getDots().size() < 3) {
markers.erase(it);
}
}
In one of test inputs (the app does image analysis) I get a segfault. I tried to debug the code (to no avail) and noticed one thing. When asking gdb to p markers.size() i receive $9 = 3. So I would expect the loop to iterate three times, but surprisingly it does it (at least) 5 times. In fifth iteration there's a segfault. What I also noticed is that it's not the dereference of *it (here it->) that causes the error. It's specifically it->getDots(), which is a simple getter.
I write in C++ very rarely, so it might be some simple mistake, but neither my debugging, nor googling brought any solution. Could you help?
I'd like to emphasize, that on various different inputs (slightly different images) this function works properly, so it's even harder for me to trace the bug down.
vector::erase invalidates all iterators pointing to the element being erased, and all elements that follow. So it becomes invalid, and ++it expression on the next loop iteration exhibits undefined behavior.
The best way to code this logic is with erase-remove idiom.
The problem is this line:
markers.erase(it);
The iterator is invalidated. But that's okay, erase returns a valid iterator:
auto it = markers.begin();
while(it != markers.end())
{
if(it->getDots().size() < 3) {
it = markers.erase(it);
}
else ++it;
}
You need to update it when you erase:
it = markers.erase(it);
since erase will "change" the vector, and your current it is no longer valid (and only do it++ if when you didn't erase it).
However, the more common way to do this is to use this type of construction:
markers.erase(std::remove(markers.begin(), markers.end(), number_in), markers.end());