vector push_back in STL? - c++

I found a sample program which i tried for STL Vectors
#include <vector>
#include <iostream>
using namespace std;
/* This one may well work with some compilers/OS, and crash with
others. Who said the STL was safe ?? */
int main() {
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
for (vector<int>::iterator i = v.begin();
i != v.end(); i++) {
cout << *i << endl;
if (*i == 1) {
v.push_back(5);
}
}
}
I was expecting result: 1 2 3 4 5
but, result is very weird - 1 0 3 4 0 0 33 0 0 0 0 0 0 0 49 0 1 2 3 4 5 5
I am guessing, this has some logic which i am missing because these don't seem like garbage values, because result is same always.
After doing push_back, is iterator getting reset or something?
I have read it somewhere that appending to a vector while iterating over it isn't a good idea. My question is why?
After some search over internet,
if (*i == 1) {
size_t diff = i-v.begin();
v.push_back(5);
i = v.begin()+diff;
}
this will solve the issue.

You are modifying the std::vector while looping through it. When calling std::vector::push_back(), if its current size() is equal to its current capacity(), the std::vector will have to reallocate its internal data storage to increase its capacity before it can store the new value. That reallocation will invalidate the loop iterator (the end() iterator is always invalidated, but you are re-evaluating it on each iteration, so it is OK in this case).
To do what you are attempting, either:
reserve() the vector's capacity before entering the loop to avoid reallocation and thus avoid invalidating the loop iterator.
reset the iterators after each reallocation.
use a std::list instead, as the loop iterator will not get invalidated by std::list::push_back().

Because std::vector::push_back might invalidate all iterators.
If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated.
For your code, you can use std::vector::reserve to avoid reallocation.
Increase the capacity of the container to a value that's greater or equal to new_cap.
int main() {
vector<int> v;
v.reserve(5); // ensure no reallocation until size() == 5
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
for (vector<int>::iterator i = v.begin();
i != v.end(); i++) {
cout << *i << endl;
if (*i == 1) {
v.push_back(5);
}
}
}
And as you said, appending to a vector while iterating over it isn't a good idea.

Some good options in existing answers, but worth mentioning another oft forgotten option when you know you're facing potential iterator invalidation due to push_back resizing beyond capacity:
for (size_t i = 0; i < v.size(); ++i) {
cout << v[i] << endl;
if (v[i] == 1)
v.push_back(5);
}
It's "C style", but simple and intuitive.

Related

Deleting an object from an vector [duplicate]

I have a std::vector<int>, and I want to delete the n'th element. How do I do that?
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
vec.erase(???);
To delete a single element, you could do:
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
// Deletes the second element (vec[1])
vec.erase(std::next(vec.begin()));
Or, to delete more than one element at once:
// Deletes the second through third elements (vec[1], vec[2])
vec.erase(std::next(vec.begin(), 1), std::next(vec.begin(), 3));
The erase method on std::vector is overloaded, so it's probably clearer to call
vec.erase(vec.begin() + index);
when you only want to erase a single element.
template <typename T>
void remove(std::vector<T>& vec, size_t pos)
{
std::vector<T>::iterator it = vec.begin();
std::advance(it, pos);
vec.erase(it);
}
The erase method will be used in two ways:
Erasing single element:
vector.erase( vector.begin() + 3 ); // Deleting the fourth element
Erasing range of elements:
vector.erase( vector.begin() + 3, vector.begin() + 5 ); // Deleting from fourth element to sixth element
Erase an element with index :
vec.erase(vec.begin() + index);
Erase an element with value:
vec.erase(find(vec.begin(),vec.end(),value));
Actually, the erase function works for two profiles:
Removing a single element
iterator erase (iterator position);
Removing a range of elements
iterator erase (iterator first, iterator last);
Since std::vec.begin() marks the start of container and if we want to delete the ith element in our vector, we can use:
vec.erase(vec.begin() + index);
If you look closely, vec.begin() is just a pointer to the starting position of our vector and adding the value of i to it increments the pointer to i position, so instead we can access the pointer to the ith element by:
&vec[i]
So we can write:
vec.erase(&vec[i]); // To delete the ith element
If you have an unordered vector you can take advantage of the fact that it's unordered and use something I saw from Dan Higgins at CPPCON
template< typename TContainer >
static bool EraseFromUnorderedByIndex( TContainer& inContainer, size_t inIndex )
{
if ( inIndex < inContainer.size() )
{
if ( inIndex != inContainer.size() - 1 )
inContainer[inIndex] = inContainer.back();
inContainer.pop_back();
return true;
}
return false;
}
Since the list order doesn't matter, just take the last element in the list and copy it over the top of the item you want to remove, then pop and delete the last item.
It may seem obvious to some people, but to elaborate on the above answers:
If you are doing removal of std::vector elements using erase in a loop over the whole vector, you should process your vector in reverse order, that is to say using
for (int i = v.size() - 1; i >= 0; i--)
instead of (the classical)
for (int i = 0; i < v.size(); i++)
The reason is that indices are affected by erase so if you remove the 4-th element, then the former 5-th element is now the new 4-th element, and it won't be processed by your loop if you're doing i++.
Below is a simple example illustrating this where I want to remove all the odds element of an int vector;
#include <iostream>
#include <vector>
using namespace std;
void printVector(const vector<int> &v)
{
for (size_t i = 0; i < v.size(); i++)
{
cout << v[i] << " ";
}
cout << endl;
}
int main()
{
vector<int> v1, v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
v2.push_back(i);
}
// print v1
cout << "v1: " << endl;
printVector(v1);
cout << endl;
// print v2
cout << "v2: " << endl;
printVector(v2);
// Erase all odd elements
cout << "--- Erase odd elements ---" << endl;
// loop with decreasing indices
cout << "Process v2 with decreasing indices: " << endl;
for (int i = v2.size() - 1; i >= 0; i--)
{
if (v2[i] % 2 != 0)
{
cout << "# ";
v2.erase(v2.begin() + i);
}
else
{
cout << v2[i] << " ";
}
}
cout << endl;
cout << endl;
// loop with increasing indices
cout << "Process v1 with increasing indices: " << endl;
for (int i = 0; i < v1.size(); i++)
{
if (v1[i] % 2 != 0)
{
cout << "# ";
v1.erase(v1.begin() + i);
}
else
{
cout << v1[i] << " ";
}
}
return 0;
}
Output:
v1:
0 1 2 3 4 5 6 7 8 9
v2:
0 1 2 3 4 5 6 7 8 9
--- Erase odd elements ---
Process v2 with decreasing indices:
# 8 # 6 # 4 # 2 # 0
Process v1 with increasing indices:
0 # # # # #
Note that on the second version with increasing indices, even numbers are not displayed as they are skipped because of i++
Note also that processing the vector in reverse order, you CAN'T use unsigned types for indices (for (uint8_t i = v.size() -1; ... won't work). This because when i equals 0, i-- will overflow and be equal to 255 for uint8_t for example (so the loop won't stop as i will still be >= 0, and probably out of bounds of the vector).
If you work with large vectors (size > 100,000) and want to delete lots of elements, I would recommend to do something like this:
int main(int argc, char** argv) {
vector <int> vec;
vector <int> vec2;
for (int i = 0; i < 20000000; i++){
vec.push_back(i);}
for (int i = 0; i < vec.size(); i++)
{
if(vec.at(i) %3 != 0)
vec2.push_back(i);
}
vec = vec2;
cout << vec.size() << endl;
}
The code takes every number in vec that can't be divided by 3 and copies it to vec2. Afterwards it copies vec2 in vec. It is pretty fast. To process 20,000,000 elements this algorithm only takes 0.8 sec!
I did the same thing with the erase-method, and it takes lots and lots of time:
Erase-Version (10k elements) : 0.04 sec
Erase-Version (100k elements) : 0.6 sec
Erase-Version (1000k elements): 56 sec
Erase-Version (10000k elements): ...still calculating (>30 min)
I suggest to read this since I believe that is what are you looking for.https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom
If you use for example
vec.erase(vec.begin() + 1, vec.begin() + 3);
you will erase n -th element of vector but when you erase second element, all other elements of vector will be shifted and vector sized will be -1. This can be problem if you loop through vector since vector size() is decreasing. If you have problem like this provided link suggested to use existing algorithm in standard C++ library. and "remove" or "remove_if".
Hope that this helped
To delete an element use the following way:
// declaring and assigning array1
std:vector<int> array1 {0,2,3,4};
// erasing the value in the array
array1.erase(array1.begin()+n);
For a more broad overview you can visit: http://www.cplusplus.com/reference/vector/vector/erase/
if you need to erase an element inside of a for-loop, do the following:
for(int i = 0; i < vec.size(); i++){
if(condition)
vec.erase(vec.begin() + i);
}
You need to use the Standard Template Library's std::vector::erase function.
Example: Deleting an element from a vector (using index)
// Deleting the eleventh element from vector vec
vec.erase( vec.begin() + 10 );
Explanation of the above code
std::vector<T,Allocator>::erase Usage:
iterator erase (iterator position); // until C++11
iterator erase( const_iterator pos ); // since C++11 and until C++20
constexpr iterator erase( const_iterator pos ); // since C++20
Here there is a single parameter, position which is an iterator pointing to a single element to be removed from the vector.
Member types iterator and const_iterator are random access iterator types that point to elements.
How it works
erase function does the following:
It removes from the vector either a single element (position) or a range of elements ([first, last)).
It reduces the container size by the number of elements removed, which are destroyed.
Note: 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.
Return value and Complexity
The return value is an iterator pointing to the new location of the element that followed the last element that was erased by the function call. This is the container end of the operation that erased the last element in the sequence.
Member type iterator is a random access iterator type that points to elements.
Here, the time complexity is linear on the number of elements erased (destructions) plus the number of elements after the last element is deleted (moving).
The previous answers assume that you always have a signed index. Sadly, std::vector uses size_type for indexing, and difference_type for iterator arithmetic, so they don't work together if you have "-Wconversion" and friends enabled. This is another way to answer the question, while being able to handle both signed and unsigned:
To remove:
template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
void remove(std::vector<T> &v, I index)
{
const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
v.erase(iter);
}
To take:
template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
T take(std::vector<T> &v, I index)
{
const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
auto val = *iter;
v.erase(iter);
return val;
}
here is one more way to do this if you want to delete a element by finding this with its value in vector,you just need to do this on vector.
vector<int> ar(n);
ar.erase(remove(ar.begin(), ar.end()), (place your value here from vector array));
it will remove your value from here.
thanks
the fastest way (for programming contests by time complexity() = constant)
can erase 100M item in 1 second;
vector<int> it = (vector<int>::iterator) &vec[pos];
vec.erase(it);
and most readable way :
vec.erase(vec.begin() + pos);

Undefined behavior while using vectors (STL), Please explain the below code output behind reason

This one may well work with some compilers/OS, and crash with others. Same code with "List" it's working fine, While using "vector" only I am facing undefined behavior output.
Is STL (vector) is safe??
Note: This is not a real-time code, I am just going through some sample programs that's it.
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
for (vector<int>::iterator i = v.begin();
i != v.end(); i++) {
cout << *i << endl;
if (*i == 1) {
v.push_back(5);
}
}
}
Output with vector:
1
0
3
4
0
0
4113
0
858851888
943206709
2617
.
.
1
2
3
4
5
5
#include <list>
#include <iostream>
using namespace std;
int main() {
list<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
for (list<int>::iterator i = v.begin();
i != v.end(); i++) {
cout << *i << endl;
if (*i == 1) {
v.push_back(5);
}
}
}
Output with list:
1
2
3
4
5
The line in the loop:
v.push_back(5);
might invalidate the iterator i (in the case a re-allocation is needed), so since then ++i is undefined behaviour.
One possibility to fix this is to reserve the vector first, so that the reallocation does not happen:
vector<int> v;
v.reserve(5); // reserve enough to keep all the pushed items
v.push_back(1);
...
The concept you are missing is "iterator invalidation". std::vector is just a dynamic array with a finite capacity. When adding a new element results in an array size greater than the capacity, a reallocation needs to happen, and this invalidates all the iterators of the vector. This is defined in the standard draft, under section "23.3.7.5 vector modifiers", which talks about insert and push_back:
Remarks: Causes reallocation if the new size is greater than the old capacity. If no reallocation happens,
all the iterators and references before the insertion point remain valid.
std::list on the other hand, is a doubly-linked list. So no reallocations need to happen to any of the elements already in the list, and only the std::list<T>::end() iterator is invalidated. But, since you are calling that method in the loop condition, your code just happens to work.

Vector Iterator not dereferencable (trying to manually reverse vector)

I'm trying to create a function which takes in a vector and simply reverses (manually). I'm aware of the existence of reverse(), but I ran into the "Vector iterator not dereferencable" problem and for educational purposes, I'd like to know what it means. I tried researching this problem and someone (on this forum) said that vect.end() is not dereferencable by definition, but from my understanding, using reverse_iterator is just reversing the ends, so following the logic; vect.rend should not be dereferencable.
vector<int> reverseVector(vector<int>);
int main()
{
vector<int> vec;
for (int i = 0; i < 11; i++)
{
vec.push_back(i);
}
vec = reverseVector(vec);
for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++)
{
cout << *it << " ";
}
cout << endl;
return 0;
}
vector<int> reverseVector(vector<int> vect)
{
vector<int>::reverse_iterator ritr;
for (ritr = vect.rbegin(); ritr != vect.rend(); ritr++)
{
vect.insert(vect.begin(), *ritr);
vect.pop_back();
}
return vect;
}
You are deleting elements from the vector (popping from the back), which invalidates the reverse iterator.
You could just iterate through half of the vector and swap the elements, lke this:
void swap(int& a, int& b) {
int tmp = a;
a = b;
b = tmp;
}
vector<int> reverseVector(vector<int> vect) {
const size_t origin_size = vect.size();
for(size_t i = 0; i < origin_size/2; ++i)
swap(vect[i], vect[origin_size - 1 - i]);
return vect;
}
Your problem has nothing to do with the dereferencability or otherwise of rend(). You're modifying the vector while iterating over it, which invalidates the iterator.
To answer your original question, a reverse_iterator isn't just "reversing the ends" compared to a forward iterator. rbegin() is end() - 1, and rend() is begin() - 1.
If you add an element to the vector, ritr may be invalidated thus the error
Vector iterator not dereferencable.
Thus its better using an index as your loop variable or better a copy(temp) vector for reverse task.
Both insert and pop_back member functions modify the vector and invalidate iterators.
A tip as design-issue: use always const-reference in a function, unless you really know what you are doing. So you will avoid stepping in traps like this. For example:
vector<int> reverseVector(const vector<int> &vect)
Now you wont have this problem, because you can not modify vect.

Range-base for and insert on a vector C++11

Is it possible to change the size of a vector in C++11 while iterating over it? Clearly the iterator will be invalidated, but can the following clean syntax still be used?
std::vector<some_type> vec;
for(auto elem : vec) {
if(condition(elem)) {
new_elem = function(elem);
vec.insert(iterator_associated_with_elem+1, new_elem);
}
//Don't insert on condition(new_elem)
}
If not, what is the cleanest code to accomplish this task?
No, you can't. The standard mandates that the raged-based for behaves like a given algorithm. This algorithm uses iterators, which get invalidated when you modify the vector.
The simplest way for me is to to use iterators. Note that when we insert, we also reassign the iterator so that we always have a valid iterator:
auto it = vec.begin();
while(it < vec.end()) {
if (condition(*it)) {
new_elem = function(*it);
it = vec.insert(it + 1, new_elem);
}
++it;
}
No, you cannot use this trick, because there is an iterator behind your range loop. Once that iterator is invalidated, you cannot reference it again.
You can use this construct if you exit the loop immediately after the insertion. Otherwise, you need to use an index-based loop that starts at the back, and goes down to zero to avoid "seeing" elements that have been inserted during the execution of the loop.
std::vector<some_type> vec;
for(int i = vec.size()-1 ; i >= 0 ; i--) {
const some_type& elem(vec[i]);
if(condition(elem)) {
vec.insert(vec.begin()+i+1, function(elem));
}
//Don't insert on condition(new_elem)
}
std::vector<int> vec = {1, 2, 3, 4, 5};
for (auto &val : vec)
{
static int i = 0;
if (val == 5)
{
vec.insert(vec.begin() + i + 1, 6);
}
++i;
}
Values of vec will then be: 1 2 3 4 5 6

possible inconsistency in std::vector while erasing an element [duplicate]

This question already has answers here:
How to delete an element from a vector while looping over it?
(6 answers)
Closed 9 years ago.
while debugging a vector, I see an inconsistency. Assume the following code which tries to remove an entry from a vector which has only one element
#include <iostream>
#include <vector>
std::vector<int> v;
void myremove(int);
int main()
{
v.push_back(10);
std::cout << "10 pushed back\n";
myremove(10);
std::cout << "done :)\n";
return 0;
}
void myremove( int a )
{
std::vector<int>::iterator it = v.begin();
int counter = 0;
for ( ; it != v.end(); it++ ) {
std::cout << "iterating for " << counter << " times and vector size is " << v.size() << "\n";
if ( a == (*it) ) {
v.erase(it);
std::cout << "removed " << a << "\n";
}
++counter;
}
}
This is what I see in the output:
$ g++ test.cpp
$ ./a.out | more
10 pushed back
iterating for 0 times and vector size is 1
removed 10
iterating for 1 times and vector size is 0
iterating for 2 times and vector size is 0
iterating for 3 times and vector size is 0
iterating for 4 times and vector size is 0
iterating for 5 times and vector size is 0
iterating for 6 times and vector size is 0
....
....
iterating for 33790 times and vector size is 0
Segmentation fault
What I understand is that when the element is removed the size will become 0, however the iterator moves one step and still it tries to reach the end but he doesn't know that he has already passed the end point.
Can someone explain more what is going on and how to avoid that?
After the call to erase() the iterator it is invalidated:
Iterators and references to the erased elements and to the elements between them and the end of the container are invalidated.
Set it to the return value of erase() instead and only increment if no removal occured:
while (it != v.end())
{
if ( a == (*it) )
{
it = v.erase(it);
std::cout << "removed " << a << "\n";
}
else
{
++it;
}
}
where the return value of erase() is:
iterator following the last removed element.
Instead of hand coding a loop to erase elements you could use std::remove_if() instead:
v.erase(std::remove_if(v.begin(),
v.end(),
[](const int i) { return i == 10; }),
v.end());
When you erase
v.erase(it);
your iterator is not valid anymore. You have to use the returned iterator from erase. Erase gives you an iterator pointing to the element that followed the element erased by the call. And you have to break the loop if you erased the last element before the loop increments it.
it = v.erase(it);
if(it == v.end())
break;
Suggestion: you can go ahead and change the for loop to a while loop. And increment the iterator explicitly (i.e. only when you have not erased anything. If you have erased the iterator is kind of incremented already).
Like this
while(it != v.end()) {
if ( a == (*it) )
it = v.erase(it);
else
++it;
}
Every insert and erase invalidates all iterators for the container. The methods return the ONLY valid iterator after inserting/erasing.
In the documentation of std::vector::erase :
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 erasing an element in your loop (which depends on an iterator) is making everything berserk. that's pretty much it !
When you call erase function the iterator is no more valid iterator, and when you increment the invalid iterator you will get spurious results.
The mistake is that you expect, after doing an erase on an iterator, that this iterator will still be in a consistent state. This is not the case, and your code illustrate precisely the situation when this occurs.
The semantic of your function is to remove all the elements of the vector equal to a. You can achieve the same result by filtering the vector. See that question for this point:
How to make std::vector from other vector with specific filter?