why vector does not updates in loop? - c++

I want to update vector 'v' so that I can iterate from count 0-100.
I know this is not allowed, but what if I want to do this only?
Is there any way?
int main() {
// your code goes here
vector<int> v;
v.push_back(1);
int count = 0;
for(int elem: v){
if(count<100)
v.push_back(count);
count++;
}
for(int elem: v)
cout << elem << endl;
return 0;
}
The output is:
1
0

As you can see from the definition of the range-based for loop, the end_expr does not update between iterations. Therefore you only have one iteration. push_back invalidates v.end() (which is what end_expr is as described in the linked page), so what you have is actually undefined behaviour.
The arguably simplest way to fill vector with 0..100 would be:
vector<int> v(101);
std::iota(v.begin(), v.end(), 0);

You should use this code instead
int count = 0;
while (v.size() < 100) {
v.push_back(count++)
}
Modifying vector while iterate through it is not allowed

Best efective way for this operation
vector<int> v;
v.resize(100);
for(unsigned int i = 0; i < v.size(); i++)
{
v[i] = i;
}
same as above.

using your code :
for(int elem: v){
if(count<100)
v.push_back(count);
count++;
}
is like using this :
int i = v.size();
for(int j = 0; j < i; j++){
v.push_back(j);
}
I don't really know why... v.size() might be keep in memory for optimization and data protection
Edit after OP comment :
Try this
int i = v.size();
for(int j = 0; j < i; j++){
if(j<100)
i = v.size();
v.push_back(count);
}

A range-based for loop produces code similar to this:
{
auto && __range = range_expression ;
for (auto __begin = begin_expr,__end = end_expr; __begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
As you can see the range will not be updated as you're iterating over your container.
Additionally you're most likely ending up with undefined behaviour because as you're pushing back values to your vector these iterators will be invalidated in case of a resize.
See #user2079303 for a better way to fill your vector.

Related

shorter notation for size_type in std::vectors

When iterating over a std::vector, I've always declared the index variable to be of size_type as in
std::vector<someReallyLengthy<TypeWith,SubTypes>> a(5);
for (std::vector<someReallyLengthy<TypeWith,SubTypes>>::size_type k = 0; k < a.size(); k++) {
// do something with a[k]
}
I'm wondering if in C++11 (or later) there's a shorthand-notation for the size_type here.
(auto won't work since it can't deduct from 0 which type it targets.)
You could use decltype:
for (decltype(a)::size_type k = 0; k < a.size(); k++) {
// do something with a[k]
}
use range-loop:
for (/*const*/ auto& el : a){
//do something with el
}
according to this answer:'size_t' vs 'container::size_type' , size_t and container::size_type are equivilant for standard STL containers, so you can also use regular size_t
for (size_t i = 0; i<a.size();i++){
//do something with a[i]
}
In addition to TartanLlama's answer which addresses your question directly, note that in c++11 you're not constricted to iterate over the indices:
for(auto &v: e)
// Do something with v
And, in case you really want the index, Nir Tzachar & I have ported much of Python's range stuff, so you can do:
for(auto &v: enumerate(e))
// v has the index and value
(see more on enumerate + examples.)
This is my way
std::vector<someReallyLengthy<TypeWith,SubTypes>> a(5);
auto length = a.size();
for (decltype(length) k = 0; k < length; k++) {
// do something with a[k]
}

Correctly erasing an element from a vector

If I have a table of vectors declared as
vector<int> table[9][9]
and I want to compare and delete the element if it already exists, would the deletion be:
for(int row = 0; row < 9; row++)//erases the current choice from the whole row
{
for(int h = 0; h < (int)table[row][k].size();h++)
{
if(table[row][k][h] == table[i][k][0])
{
table[row][k].erase(table[row][k].begin() + h);
}
}
}
I thought this would work, but I'm not 100% because I tried to delete every element using this technique and it didn't work, for those of you who want to see the code I used to delete all the elements, then it is:
for(int i = 0; i < 9; i++)
for(int k = 0; k < 9; k++)
for(int n = 0; n < table[i][k].size();n++)
table[i][k].erase(table[i][k].begin + n);
this method did not work, so I used clear instead.
I don't know what choice and k are, but to erase all values from a vector v that are equal to a particular value val use the "erase-remove idiom":
v.erase(
std::remove(v.begin(), v.end(), val),
v.end()
);
Hence, to do this same thing for all vectors in table:
for (auto &row : table) {
for (auto &v : row) {
v.erase(
std::remove(v.begin(), v.end(), val),
v.end()
);
}
}
If you have a more complicated condition than equality, use remove_if in place of remove. But in your case, the extra condition involving puzzle doesn't use the loop variable h, so I think you can test that before looking in the vector:
if (puzzle[row][k] == 0) {
// stuff with erase
}
In C++03 you can't use "range-based for loops" for (auto &row : table). So if you don't have C++11, or if you need the index for use in the puzzle test, then stick with for(int i = 0; i < 9; i++).

Interator and average in C++

I'm trying to learn to use iterator with vectors in C++ by, for example computing the average of a vector.
Yet this code does not give the proper answer and I cannot figure out why !
double average(vector<double> const &v)
{
vector<double>::size_type taille = v.size();
double sum = 0;
for(vector<double>::const_iterator i = v.begin(); i != v.end(); ++i)
sum += v[*i];
return sum/taille;
}
Can anybody give me a hint ?
Thanks a lot in advance ! Bye :)
In C++, iterators imitate the behaviors of pointers (to some degree). So if it is an iterator to an element, you access the element by dereferencing it as *it.
That means, instead of this:
sum += v[*i];
you should write this:
sum += *i; //just dereference the iterator!
Hope that helps.
Accessing vector items through an iterator is simply *i, not v[*i]. The form you've used requires accessing with index:
for (size_t i = 0; i < v.size(); i++) sum += v[i];
And your code should look like:
for(vector<double>::const_iterator i = v.begin(); i != v.end(); ++i)
sum += *i;
^^^^ note this
The iterator actually points to the object. Proper way to iterate is:
double average(vector<double> const &v)
{
vector<double>::size_type taille = v.size();
double sum = 0;
for(vector<double>::const_iterator i = v.begin(); i != v.end(); ++i)
sum += *it;
return sum/taille;
}
In C++11 you can do this too:
double average(vector<double> const &v)
{
double sum = 0;
for(const double &d : v)
sum += d;
return sum/v.size();
}

How to write a for loop that uses both an iterator and an index counter?

I have a function that looks like this:
void myclass::myfunc()
{
int i;
for( std::vector<Foo>::iterator it = var.begin(), i = 0; it < var.end(); it++, i++ )
{
/* ... */
}
}
I'm getting this error:
Cannot convert from int to std::_Vector_iterator<>
What is wrong with this code?
The issue is with this part of the for loop:
std::vector<Foo>::iterator it = var.begin(), i = 0
C++ is interpreting this not as two comma-separated statements, but as a variable declaration for a variable named it that's an iterator, and as a new declaration of a variable i that's an iterator and initialized to 0. The error is because you can't initialize a vector iterator to 0.
To fix this, you'll need to hoist the definition outside of the loop:
int i = 0;
std::vector<Foo>::iterator it = var.begin();
for(; it < var.end(); it++, i++ )
{
// ...
}
Or move the initialization of i outside the loop:
int i = 0;
for( std::vector<Foo>::iterator it = var.begin(); it < var.end(); it++, i++ )
{
// ...
}
Here's another option. If you need to keep track of the index into the vector you're currently looking at, you could consider just using a counting for loop (without the iterator), or using just the iterator and using iterator subtraction to recover the index:
for (auto it = var.begin(); it != var.end(); ++it) {
// current position is it - var.begin();
}
And, finally, if you have a C++20-compliant compiler, you could eliminate the iterator entirely and use an enhanced for loop in the following way:
/* Requires C++20 */
for (int i = 0; Foo f: var) {
/* Do something worthwhile with f. */
i++;
}
Hope this helps!
You can do it like this:
int i = 0;
for( std::vector<int>::iterator it = v.begin(); it < v.end(); ++it, ++i){}
Get rid of the i=0; part (at least inside the loop header).
Also, if you insist on doing this at all, consider using:
for (auto it : var)
or:
for (auto it = var.begin(); it != var.end(); ++it)
...instead. Since you're using a random access iterator anyway, what you have as i is equivalent to it - var.begin(). Conversely, you could just use:
for (int i=0; i<var.size(); i++)
...and get an iterator when needed as var.begin() + i.
Depending on what's in the body of the loop, you probably want to get rid of the loop entirely, and replace it with an algorithm though.
Double iteration:
using std::begin; using std::end;
for (auto p = std::make_pair( begin(var), 0 ); p.first != end(var); ++p.first, ++p.second ) {
/* ... */
}
double iteration with named indexes/iterators:
using std::begin; using std::end;
int i;
std::vector<Foo>::iterator it;
for (std::tie( it, i ) = std::make_pair( begin(var), 0 ); it != end(var); ++it, ++i ) {
/* ... */
}
or bind the above pair on each iteration to better named variables:
using std::begin; using std::end;
for (auto p = std::make_pair( begin(var), 0 ); p.first != end(var); ++p.first, ++p.second ) {
auto const& it = p.first;
int i = p.second;
}

c++ map doesn't return end() even though it should

In my code I have a map (tBoxes) with vector<int> begin the key and set< pair<int,int> > being the value.
For some reason, the program crash with segmentation fault when I try to access a specific element of the map which is empty. If I run the program through valgrind all is well (that is how I know the element is empty). Also, valgrind doesn't state any memory leak. The loop I'm using is a naive one:
map<vector<int>,set<int, int> > tBoxes;
/*populate boxes*/
vector<int> t(3,0);
set<pair<int, int> >::iterator it;
for(int i = mini; i <= maxi; i++){
t[0] = i;
for (int j = minj; j <= maxj; j++){
t[1] = j;
for (int k = mink; k <= maxk; k++){
t[2] = k;
it = tBoxes[t].begin();
while (it != tBoxes[t].end()){
it++;
}
}
}
}
Edit:
The code is not a direct copy-pate from my file since I use weird variable names.
I suspect this is an issue with memory allocation of the map but I don't know how to fix this. Also, the value is a set and not a vector.
for (int k = mink; k <= maxj; k++){ // should'n it be maxk?
The old "copy-and-paste the for" error :D
EDIT: Op changed the code and corrected what i pointed out, so this answer is no longer valid...
EDIT:
complete rewrite to insert an int into a set of ints which is then inserted into a map of vectors of ints to sets of ints. (Sic.) Then retrieving the original int.
int main( int argc, char *argv )
{
map< vector<int>, set<int> > tBoxes;
vector<int> vecInsert( 3, 0 );
set<int> setInsert;
setInsert.insert( 666 );
tBoxes.insert( std::make_pair( vecInsert, setInsert ) );
///////////////////////////////////////////////////////////
vector<int> vecLookup( 3, 0 ); //identical to vecInsert
set<int> setLookup = tBoxes[vecLookup]; //the set mapped by the 'key' vector above
set<int>::iterator iter = setLookup.begin(); //the first element in the set
if( iter != setLookup.end() )
{
int i = *iter;
if( i == 666 )
{
//eureka!!
}
}
return 0;
}