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);
Related
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.)
Why does the following code crash? And what should I do when I am iterating via reverse iterator. How do I erase individual elements then?
deque q;
q.push_back(4);
q.push_back(41);
q.push_back(14);
for (auto it = q.begin(); it != q.end();) {
auto current = it;
q.erase(current);
it++;
}
Why does the following code crash ? How do I erase individual elements then ?
std::deque::erase invalidates iterators.
All iterators and references are invalidated, unless the erased elements are at the end or the beginning of the container, in which case only the iterators and references to the erased elements are invalidated.
The past-the-end iterator is also invalidated unless the erased elements are at the beginning of the container and the last element is not erased.
In your code, the iterators to the element to be erased (i.e. it and current) will become invalid after q.erase(current), then it++ will lead to UB.
You could make use of the return value of std::deque::erase
Iterator following the last removed element. If the iterator pos refers to the last element, the end() iterator is returned.
for (auto it = q.begin(); it!=q.end(); )
{
it = q.erase(it);
}
And what should I do if I am iterating via reverse iterator.
Because std::deque::erase doesn't accept reverse_iterator as parameters, you need to use base() to convert it to normal iterator (pay attention to the position conversion). Such as
for (auto it = q.rbegin(); it!=q.rend(); )
{
it = std::make_reverse_iterator(q.erase((++it).base()));
}
As per C++11 23.3.3.4 deque modifiers /4, deque iterators become invalid if you delete certain elements.
An erase operation that erases the last element of a deque invalidates only the past-the-end iterator and all iterators and references to the erased elements.
An erase operation that erases the first element of a deque but not the last element invalidates only the erased elements.
An erase operation that erases neither the first element nor the last element of a deque invalidates the past-the-end iterator and all iterators and references to all the elements of the deque.
In your case, you're usually only ever erasing the first element so it will only invalidate that element. That means the it++ is invalid and you should instead use something like:
it = q.erase(it);
inside the loop, since the erase call itself returns an "adjusted" iterator. This will also work when removing the last element.
However, since your code is totally clearing the list (assuming it's not a cut down version of something which needs to process each element), you can ditch the loop altogether and just use:
q.clear();
As the other answerers have already pointed out, erasing elements from the queue will invalidate the iterators you are using to iterate its elements. Thus it fails.
But I assume that you don't intend to erase all elements in the queue, in which case you probably would have rather used:
q.erase(q.begin(), q.end());
or
q.clear();
Therefore, I'd like to suggest using another technique, that can be used to delete items matching certain criteria from a queue: the erase-remove idiom.
Here, the functions std::remove(...) and std::remove_if(...) are used to move the items to be deleted (matching certain criteria) to the end of the container. The range-based version of q.erase(...) is then used to delete the items.
Here's an example:
#include <deque>
#include <algorithm>
#include <iostream>
// predicate function for removal of elements
bool greater_three(int x) {
return x > 3;
}
int main() {
std::deque<int> q = {1,2,3,4,5};
for (auto i : q) std::cout << i << " "; std::cout << "\n";
// delete all items with value 3
q.erase(std::remove(q.begin(), q.end(), 3), q.end());
for (auto i : q) std::cout << i << " "; std::cout << "\n";
// delete all items with value > 3
q.erase(std::remove_if(q.begin(), q.end(), greater_three), q.end());
for (auto i : q) std::cout << i << " "; std::cout << "\n";
}
The output is:
$ g++ test.cc -std=c++11 && ./a.out
1 2 3 4 5
1 2 4 5
1 2
For reference:
http://en.cppreference.com/w/cpp/container/deque/erase
http://en.cppreference.com/w/cpp/container/deque/clear
http://en.cppreference.com/w/cpp/algorithm/remove
q clearly doesn't support removing elements while iterating through them.
I am trying to access the element of a vector using the iterator. But I get strange outputs.
std::vector<int> ivec{ 7, 6 , 8, 9} ;
std::vector<int>::iterator beg = ivec.begin();
std::vector<int>::iterator last = ivec.end();
std::cout << *beg << *last << std::endl;
But, In the above case the program shows me error: debug assertion failed. Vector iterator not dereferencable. and this error is particularly for *last. If I just print *beg that seems to wrong fine. But can't dereference the last one.
Other problem I get with iterator is during increment.
std::vector<int>::iterator beg = ivec.begin();
cout << *(beg++) ; // in this case it prints me value of 7
cout << *(++beg) ; // in this case it print me the right value of second place i.e. is 6
cout << *(beg+=1) ; // in this case we also print the second value i.e. 6
end iterators are not iterators that you can de-reference. They point past the last element into the container. There's a good reason why this needs to be true; but long and short, the end iterator does not actually point to any element. If you want the last element, you need to decrement the end iterator.
For your first example, std::vector<T>::end points to the theoretical element after the actual last element, so dereferencing it does not make sense. It is primarily used for checking when you have got past the end of the vector in a loop.
For your second example, the results are as you would expect:
cout << *(beg++) ; //increments beg after dereferencing
cout << *(++beg) ; //increments beg before dereferencing
cout << *(beg+=1) ; //dereferences the result of adding one to beg
As it is stated in here,
Return iterator to end, Returns an iterator referring to the past-the-end element in the vector container.
The past-the-end element is the theoretical element that would follow the last element in the vector. It does not point to any element, and thus shall not be dereferenced.
Because the ranges used by functions of the standard library do not include the element pointed by their closing iterator, this function is often used in combination with vector::begin to specify a range including all the elements in the container.
If the container is empty, this function returns the same as vector::begin.
Okay, so I am new to this, and I am having trouble understanding this.
I made this code,
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main (void)
{
vector <int> a;
int i;
a.push_back(1);
a.push_back(2);
a.push_back(3);
a.push_back(4);
a.push_back(5);
vector <int>::iterator position = find(a.begin(),a.end(),6);
cout<<*position<<"\n";
return 0;
}
I read everywhere that the find function if it doesnt find anything returns the iterator to the end of the vector. So, when, I do this, and search the value 6 which is not present in the vector, it should return the iterator to the end of the vector which is actually 5. On printing the actual value, it should then print 5 but it prints 0. Why is it that if it returns the iterator to the last value if find doesnt find anything in the vector relating to the value, then it prints 0?
No, it will not return the end of the vector it will return vector.end()
The former implies the last element of the vector, which would be 5.
The latter, vector.end(), is past the end of the vector
This adds slight confusion because vector.begin() does indeed point to the first element of the vector, but this is necessary due to the way you can iterate these containers.
Why is it that if it returns the iterator to the last value if find doesnt find anything in the vector relating to the value, then it prints 0
0 is a garbage value that you get when you dereference the end iterator of the vector. This is undefined behavior, so you could potentially get any number at all. A proper code looks like this:
vector <int>::iterator position = find(a.begin(),a.end(),6);
if (position != a.end()) {
cout<<*position<<"\n";
} else {
cout << "not found" << endl;
}
Once you get the result, you need to compare it to a.end() to see if the result is valid. If the result is not valid, you may not dereference the iterator to avoid undefined behavior.
As you can see in the documentation for vector::end(), the end() iterator is not the same as the last element in the vector. Rather, it is past the last element. Accessing that element results in undefined behavior.
Help on vector says of front()
Returns a reference to the first element in the vector container.
Unlike member vector::begin, which returns an iterator to this same element, this > function returns a direct reference.
Help on vector says of begin()
Returns an iterator referring to the first element in the vector container.
Notice that unlike member vector::front, which returns a reference to the first element, > this function returns a random access iterator.
And this code outputs:
char arr[] = { 'A', 'B', 'C' };
vector<char> vec(arr, arr+sizeof(arr));
cout << "address of vec.front() " << (void*)&vec.front() << endl;
cout << "address of vec.begin() " << (void*)&vec.begin() << endl;
address of vec.front() 00401F90
address of vec.begin() 0030F494
I don't understand what 'direct reference' means? In the case of begin() isn't a random access iterator just a pointer?
Can someone please point out the difference?
According to Stroustrup in The C++ Programming Language, Section 16.3.3; think of front() as the first element and begin() as a pointer to the first element.
In the case of begin() isn't a random access iterator just a pointer?
No, an iterator has some pointer semantics, but it's actually a class.
And even if it was, that should answer the question. It's like asking why the address of a pointer isn't the same as the address of the object it points to.
You'd get the same value if you dereference the iterator, which will give you the first element:
&(*vec.begin())
because
*vec.begin() == vec.front()
For a vector, begin() and end() return random access iterators. They might return a plain pointer; that's okay, because it meets the requirements to be a random access iterator. In particular, you can write *begin() to get a reference to the first object in the sequence (assuming there is one). front() gives you a reference to the first object in the sequence, without going through the intermediate iterator. Like this:
vector<int> v;
v.push_back(3);
int i = *v.begin(); // i == 3
int j = v.front(); // j == 3
Assuming you have at least 1 element in the vector,
vec.front()
is the same as
*vec.begin()
To keep it clear in your mind, always try to remember the following two lines assuming that you have a vector from STL called v:
v.front() = * v.begin()
&&
v.back() = * v.end()
that means if you have a vector:
v = {1,2,3,4};
and you have an iterator called IT, and you want to access the first and the last element
you can either do:
IT = v.begin();
std::cout<<*IT<<std::endl; // output : 1
IT = v.end();
std::cout<<*IT<<std::endl; // output : 4
or you can easily do this:
std::cout<<v.front<<std::endl; // output : 1
std::cout<<v.back<<std::endl; // output : 4
both will print the same output, the difference is just between if you want to use an iterator or not.