Reputation: 361
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]
Upvotes: 0
Views: 199
Reputation: 3341
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.)
Upvotes: 2
Reputation: 586
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
Upvotes: 2
Reputation: 155323
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.
Upvotes: 5