I used poll() with std::vector.
registed listen socket.
std::vector<struct pollfd> fds;
fds.push_back(server_sock);
and add new client socket or connected client session do something.
// poll() ...
for(std::vector<struct pollfd>::reverse_iterator it = fds.rbegin(); it != fds.rend(); it++) {
if (it->fd == server_sock) {
struct pollfd newFd;
newFd.fd = newClient;
newFd.events = POLLIN;
fds.push_back(newFd);
} else {
// do something.
}
}
but the reverse_iterator does not work properly when there is a 1 or 2 or 4 vector's element. I don't understand why this work.
attached sample code.
typedef struct tt_a {
int a;
short b;
short c;
} t_a;
vector<t_a> vec;
for (int i = 0; i < 1; i++) {
t_a t;
t.a = i;
t.b = i;
t.c = i;
vec.push_back(t);
}
for(vector<t_a>::reverse_iterator it = vec.rbegin(); it != vec.rend(); it++) {
if (it->a == 0) {
t_a t;
t.a = 13;
t.b = 13;
t.c = 13;
vec.push_back(t);
}
printf("[&(*it):0x%08X][it->a:%d][&(*vec.rend()):0x%08X]\n",
&(*it), it->a, &(*vec.rend()));
}
printf("---------------------------------------------\n");
for(vector<t_a>::reverse_iterator it = vec.rbegin(); it != vec.rend(); ++it) {
if (it->a == 3) {
it->a = 33;
it->b = 33;
it->c = 33;
}
printf("[&(*it):0x%08X][it->a:%d][&(*vec.rend()):0x%08X]\n",
&(*it), it->a, &(*vec.rend()));
}
result:
[&(*it):0x01ADC010][it->a:0][&(*vec.rend()):0x01ADC028]
[&(*it):0x01ADC008][it->a:33][&(*vec.rend()):0x01ADC028]
[&(*it):0x01ADC000][it->a:0][&(*vec.rend()):0x01ADC048]
If vector has 5 elements, it works normally.
[&(*it):0x007620A0][it->a:4][&(*vec.rend()):0x00762078]
[&(*it):0x00762098][it->a:3][&(*vec.rend()):0x00762078]
[&(*it):0x00762090][it->a:2][&(*vec.rend()):0x00762078]
[&(*it):0x00762088][it->a:1][&(*vec.rend()):0x00762078]
[&(*it):0x00762080][it->a:0][&(*vec.rend()):0x00762078]
---------------------------------------------
[&(*it):0x007620A8][it->a:13][&(*vec.rend()):0x00762078]
[&(*it):0x007620A0][it->a:4][&(*vec.rend()):0x00762078]
[&(*it):0x00762098][it->a:33][&(*vec.rend()):0x00762078]
[&(*it):0x00762090][it->a:2][&(*vec.rend()):0x00762078]
[&(*it):0x00762088][it->a:1][&(*vec.rend()):0x00762078]
[&(*it):0x00762080][it->a:0][&(*vec.rend()):0x00762078]
push_back invalidates iterators when it causes size to exceed capacity:
If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated. Otherwise only the past-the-end iterator is invalidated.
Basically, if you must push_back, make sure to reserve ahead of time so you don't invalidate your iterator.
Your program most likely has crashed. You are manipulating the container while still iterating over it.
[&(*it):0x01ADC008][it->a:33][&(*vec.rend()):0x01ADC028]
You can see junk '33' while it should be '13'.
And why are you even trying to dereference the end iterator
&(*vec.rend())
This basically will be a junk irrespective of the vector size. Its an undefined behavior and will crash your application randomly.
As shadow points out fix the vector size before iterating, but still I am not sure how that will fix your code as your example has other issues that will cause seg fault
For normal (forward, not reverse) vector iterators, inserting into the vector invalidates any iterators that point to anywhere at or after the point of insertion. Furthermore, if the vector must be resized, all iterators are invalidated.
This alone could explain your problems, as because you have not reserved space in your vector (by calling vec.reserve(SIZE)), any of your push_back calls could trigger a resize and invalidate your iterators, which will result in undefined behaviour when you try to use them afterwards.
However, reverse iterators are more complicated, and the same guarantee does not hold for reverse iterators, and I believe any insertion may invalidate them.
Internally, a reverse iterator holds a forwards iterator to the element after the one that it points to. When dereferenced, the reverse iterator decrements this forwards iterator and returns its dereferenced value. So rbegin() internally has a copy of end(), and rend() has a copy of begin(). The above rules for forward iterator invalidation then imply that at the very least, a reverse iterator will be invalidated if an insertion occurs at any point up to one element after the location of the reverse iterator. So if you have an iterator pointing to index 0 in a length 1 vector, push_back will insert to index 1, which will invalidate the iterator. If you then continue to use that iterator (such as when dereferencing it in the subsequent printf call) then you will have undefined behaviour.
Undefined behaviour means anything could happen, and very commonly different systems will produce different behaviour. Do not assume that just because this code runs as expected on your system with an initial vector size of 5 that it will work on other systems. Any code invoking undefined behaviour is inherently fragile, and should be avoided.
For me (running Visual Studio 2015), I get a crash at the printf line regardless of the size of the vector. If I call vec.reserve(10) to eliminate the resizing-invalidation issue, then it only crashes when vec is initially of length one.
Additionally, you are dereferencing vec.rend() in your printf arguments, which is also undefined behaviour, even if you are just trying to get an address out of it. (I had to comment out this to get your code to run, otherwise it would crash every time even without the push_back call.)
Related
Consider the following code
std::set<int> int_set = {1, 2, 3, 4};
for(const auto& key : int_set)
{
if(key == 2)
{
int_set.erase(key);
break;
}
}
The code runs as expected, but is it safe?
It feels wrong to be using a reference to a key to erase itself from a set, as presumably once the erase has happened the reference is no longer valid.
Another code snippet with the same potential problem would be
std::set<int> int_set = {1, 2, 3, 4};
const auto& key = *int_set.find(2);
int_set.erase(k);
This is safe in the code provided since you break out of the loop without attempting to use the reference (key) again (nor implicitly advance the underlying iterator that for-each loops are implemented in terms of, which would happen if you did not break/return/throw/exit()/crash, when you looped back to the top of the loop) after the call to erase. key itself is only needed to find the element to remove; until that element is removed, it's valid, once it's removed, it's not used again by erase (it already found the element to erase, there's no possible use for it after that point).
If you tried to use key after the erase, you'd be using a dangling reference, invoking undefined behavior. Similarly, even allowing the loop to continue (implicitly advancing the underlying iterator) would be illegal; the iterator is invalid, and the implicit advancing of the iterator when you returned to the top of the loop would be equally invalid. The safe way to erase more than one element as you iterate would be to switch from for-each loops (that are convenient, but inflexible) to using iterators directly, so you can update them with the return value of erase, e.g.:
for(auto it = int_set.begin(); it != int_set.end(); /* Don't increment here */)
{
if (predicate(*it)) {
it = int_set.erase(it); // In C++11 and higher, erase returns an iterator to the
// element following the erased element so we can
// seamlessly continue processing
} else {
++it; // Increment if we didn't erase anything
}
}
Of course, as noted in the comments, if you only need to remove one element with a known value, the whole loop is pointless, being a slow (O(n) loop + O(log n) erase) way to spell:
int_set.erase(2); // Returns 1 if 2 was in the set, 0 otherwise
which is a single O(log n) operation.
I have a map which elements are vectors.I have to delete from these vectors all elements which are equal to special number num
std::map<size_t,std::vector<size_t> > myMap;
for (std::map<size_t,std::vector<size_t> >::iterator itMap = myMap.begin();itMap != myMap.end();++itMap )
{
for (std::vector<size_t>::iterator itVec = itMap->second.begin();itVec != itMap->second.end();)
{
auto itNextVec = itVec;
++itNextVec;
if (*itVec == num)
{
itMap->second.erase(itVec );
}
itVec = itNextVec;
}
}
The code causes run-time exepssion .In VS - vector iterators incompatible.
Can someone point what is the cause for that?
Thanks
std::vector::erase returns an iterator to the next position of the list, and so when you do an erase you should make your iterator equal to the returned value.
The only thing that you have to consider is that the returned iterator could be the end so you should check for that.
What I personally like to do is is after doing in an erase and I get the next iterator position, I go back to the previous position of the returned iterator and than call a continue on the for loop
Example:
#include <vector>
#include <iostream>
int main()
{
std::vector<int> myInt;
myInt.push_back(1);myInt.push_back(2);myInt.push_back(3);
for(auto iter = myInt.begin();
iter != myInt.end();
++iter)
{
if(*iter == 1)
{
iter = myInt.erase(iter);
if(iter != myInt.begin())
{
iter = std::prev(iter);
continue;
}
}
std::cout << *iter << std::endl;
}
}
But doing an erase inside of a iterator loop is frowned upon because it invalidates the old iterator and that could cause a lot of issues if you didn't plan for them.
erasing will invalidate the iterator
Iterator validity
Iterators, pointers and references pointing to position (or first) and beyond are
invalidated, with all iterators, pointers and references to elements before position (or
first) are guaranteed to keep referring to the same elements they were referring to
before the call.
You can't trivially erase an item from a collection while iterating over it. Think a little about it, your removing what itVec "points" to, after the removal itVec no longer "points" to an element, so it no longer have a "next" pointer.
If you check e.g. this reference, you will see that the erase function returns an iterator to the next element. Continue the loop with this one (without increasing it of course).
Consider either using a different collection class than vector or creating a new vector with the desired items removed rather than removing from existing vector.
The following piece of c++ code gives
int main()
{
vector <int> myvect(3,0);
vector <int> :: iterator it;
it = myvect.begin();
myvect.insert(it,200);
myvect.insert(it+5,400); //Not sure what 5 makes the difference here
cout << myvect[0] << endl << myvect[1];
}
Output :
200
400
And the same code with minor changes gives
int main()
{
vector <int> myvect(3,0);
vector <int> :: iterator it;
it = myvect.begin();
myvect.insert(it,200);
myvect.insert(it+4,400); //Not sure what 4 makes the difference here
cout << myvect[0] << endl << myvect[1];
}
Output:
400
200
Can someone tell me why adding 4 or 5 to the iterator changes the order of elements?
Thanks
Your program has Undefined Behavior.
You are creating a vector of 3 elements (all initialized to 0), and you are inserting elements at position v.begin() + 5, which is beyond the end of the vector.
Moreover, you are using an iterator (it) after inserting an element before the position it points to. According to Paragraph 23.3.6.5/1 of the C++11 Standard:
[...] If no reallocation happens, all the iterators and references before the insertion point remain valid. [...]
Therefore, iterator it itself is not guaranteed to be valid after the statement myvect.insert(it, 200), and using it in the next instruction (myvect.insert(it + 4, 400)) is again Undefined Behavior.
You cannot expect anything of a program with Undefined Behavior. It may crash, give you bizarre results, or (in the worst case) behave just as you would expect.
The member function vector::insert(const_iterator, const value_type&) requires a valid iterator that refers to the vector but it+4 and it+5 are not valid iterators.
Before the first insertion, it+3 is a valid (non-dereferencable) iterator, pointing just past-the-end of the vector sequence, but it+4 is invalid. After the insertion it might get invalidated, in which case no expression using it is valid, certainly not it+5 because the sequence only has four elements at that point.
The code would be valid if changed like so:
it = myvect.begin();
myvect.insert(it,200);
it = myvect.begin(); // make it valid again
myvect.insert(it+4,400);
The code:
for(x=abc.begin();x!=abc.end();x++)
{
if(-----)
{
----
abc.erase(x);
}
}
And the error is :::
Dangerous iterator usage
After erase the iterator is invalid so dereferencing it or comparing it with another iterator is invalid.
what is the wrong usage in using erase function in the above code?
The itarator x is invalid after deleting the corresponding value from abc. This should fix it:
x = abc.begin();
while(x != abc.end())
{
if (-----)
{
----
x = abc.erase(x);
// skipped only to next item
}
else
{ // skip only to next item
++x;
}
}
The erase template functions of STL containers return the next element, or end().
Edit: Thanks for comment by templatetypedef.
You're using x as the control variable in the loop. Since it is invalidated by erase(), you cannot be sure that it is safe (or meaningful) to subsequently increment it at the top of the loop.
x is a pointer into abc. Once you've erased the item pointed to by x, what is x supposed to be pointing to and how is x++ supposed to work?
You said nothing about the container you are iterating on. On the type of the container depends which iterators are invalidated. For sure iterator to erased element is invalid, but for example in std::vector all iterators past erased element will be invalid (including end()). And for unknown reason although set::erase invalidates only iterator to erased element, it does not return the iterator to next element.
So with std::set:
while (x != abc.end()) // end() will not change and even can be stored
{
if (...)
abc.erase(x++); // increments before erasing
else
++x;
}
There have been a few questions regarding this issue before; my understanding is that calling std::vector::erase will only invalidate iterators which are at a position after the erased element. However, after erasing an element, is the iterator at that position still valid (provided, of course, that it doesn't point to end() after the erase)?
My understanding of how a vector would be implemented seems to suggest that the iterator is definitely usable, but I'm not entirely sure if it could lead to undefined behavior.
As an example of what I'm talking about, the following code removes all odd integers from a vector. Does this code cause undefined behavior?
typedef std::vector<int> vectype;
vectype vec;
for (int i = 0; i < 100; ++i) vec.push_back(i);
vectype::iterator it = vec.begin();
while (it != vec.end()) {
if (*it % 2 == 1) vec.erase(it);
else ++it;
}
The code runs fine on my machine, but that doesn't convince me that it's valid.
after erasing an element, is the iterator at that position still valid
No; all of the iterators at or after the iterator(s) passed to erase are invalidated.
However, erase returns a new iterator that points to the element immediately after the element(s) that were erased (or to the end if there is no such element). You can use this iterator to resume iteration.
Note that this particular method of removing odd elements is quite inefficient: each time you remove an element, all of the elements after it have to be moved one position to the left in the vector (this is O(n2)). You can accomplish this task much more efficiently using the erase-remove idiom (O(n)). You can create an is_odd predicate:
bool is_odd(int x) { return (x % 2) == 1; }
Then this can be passed to remove_if:
vec.erase(std::remove_if(vec.begin(), vec.end(), is_odd), vec.end());
Or:
class CIsOdd
{
public:
bool operator()(const int& x) { return (x % 2) == 1; }
};
vec.erase(std::remove_if(vec.begin(), vec.end(), CIsOdd()), vec.end());