Why is vector::clear not working inside foreach loop? - c++

My code:
vector<int> v[10];
const int x = 3;
void clearBySimpleLoop(){
for (int i = 0; i < x; i++){
v[i].clear();
}
}
int main()
{
for (int i = 0; i < x; i++){
v[i].push_back(11+i);
v[i].push_back(11+i+1);
v[i].push_back(11+i+2);
}
for (auto vec : v) vec.clear(); //#01. Contents are not cleared. Size of the contained vectors remains same.
clearBySimpleLoop(); //#02. Contents are cleared. Size of the contained vectors becomes zero.
return 0;
}
Question is why does the code inside the foreach loop (#01) fails to clear the vector in the array, while a simple for loop (#02) does it successfully?
Demo: https://onlinegdb.com/B1m8-2jG4

When you write
for (auto vec : v) vec.clear(); //
then auto gets deduced as std::vector<int>, hence vec are copies of the elements of v. You clear the copies, but leave the actual elements unchanged. If you want to operate on the elements themself you have to use references:
for (auto& vec : v) vec.clear();
My personal rule of thumb is to always mention pointerness, constness and referenceness explicitly when using auto. I think it makes usages of auto much more readable, but thats just my opinion. Note that here you have no choice, but if you'd follow the rule you could have realized more easily that vec are values, not references.

Related

C++ vectors - Is there any way I can copy a vector inside a for loop and use it outside of the loop?

I have a do-while loop which copies a vector before it clears it, to make room for the for loop to run again. I have tried the following (with declaring the vector as a global one):
std::vector<int> z;
// bunch of code
do {
// bunch of code
double v_size = v.size();
for (int i = 0; i < v_size; i++) {
z.push_back(v[i]);
}
} while (true);
This does work, but my understanding is that its bad programming practise and may get some bizarre results on different compilers. I also get an error message (on the line where the push_back is):
Implicit conversion changes signedness: 'int' to
'std::__1::vector<int, std::__1::allocator<int> >::size_type' (aka
'unsigned long')
I am really new to C++ and coding in general. So, if there are any veterans here, willing to help or figure this out, it would be highly appreciated.
Here is some additional code in more context to clarify:
#include <iostream>
#include <vector>
int main(){
std::vector<int> v;
std::vector<int> z;
int option;
std::cout << "Enter option";
std::cin >> option;
do {
double v_size = v.size();
for (int i = 0; i < v_size; i++) {
z.push_back(v[i]);
}
// Clearing vector v to let the loop run again, and the vector
// need to be empty for the real code to work.
v.clear();
} while (option != 1);
// Use the vector Z for all the total values that
// circled through vector v.
}
The error you are getting is because you are trying to compare int and double;
if you are trying to copy the contents of one vector into another. What you are doing is not the best way.
There are a few methods
Source: Ways to copy a vector into another in C++
Using the = operator
std::vector<int> vec1{1,2,3,4,5};
std::vector<int> vec2 = vec1;
Passing vector by a constructor
std::vector<int> vec1{1,2,3,4,5};
std::vector<int> vec2(vec1);
Using std::copy
std::vector<int> vec1{1,2,3,4,5};
std::vector<int> vec2;
std::copy(vec1.begin(), vec1.end(), back_inserter(vec2));
assign
std::vector<int> vec1{1,2,3,4,5};
std::vector<int> vec2;
vec2.assign(vec1.begin(), vec1.end());
Iterating through a vector
Just some extra knowledge I believe can help you
Maybe you already know this, maybe you don't. But iterating through a vector the way you have mentioned is also not the best and there is a better way.
C++11 Introduced Range-based loops. A nicer and cleaner way to iterate over a range of values.
Syntax
It goes like this
for ( range_declaration : range_expression )
in context to our example
std::vector<int> vec{4,62,36,54};
for (auto i:vec){
std::cout << i;
}
If you don't want to modify the values, it is a good practice to use
const auto i:vec rather than auto i:vec. Check this out for more information

How do I push vectors by reference?

This code below doesn't work because I push_back the vectors a and b to the vector vector and then alter the vectors a and b. I want to alter the vectors a and b so that the vector vector suffers the same modifications. How do I do this?
#include <iostream>
#include <vector>
int main()
{
std::vector<std::vector<int>>vector;
std::vector<int>a;
std::vector<int>b;
vector.push_back(a);
vector.push_back(b);
for (int i = 1; i <= 10; i++)
a.push_back(i);
for (int i = 11; i <= 20; i++)
b.push_back(i);
std::cout << vector[1][0];
std::cin.get();
}
You can use std::reference_wrapper (since C++11).
std::reference_wrapper is a class template that wraps a reference in a copyable, assignable object. It is frequently used as a mechanism to store references inside standard containers (like std::vector) which cannot normally hold references.
e.g.
std::vector<std::reference_wrapper<std::vector<int>>> v;
std::vector<int> a;
std::vector<int> b;
v.push_back(a);
v.push_back(b);
for (int i = 1; i <= 10; i++)
a.push_back(i);
for (int i = 11; i <= 20; i++)
b.push_back(i);
std::cout << v[1].get()[0]; //11
LIVE
Note that if the vector has longer timelife than a and b, then when a and b get destroyed the references stored in the vector become dangled.
Create v (vector is not a good name since it shares with the library and makes the code confusing) to be a vector of vector pointers (since a vector of references is not possible):
std::vector<std::vector<int> *> v; //declare as vec of vec pointers
...
v.push_back(&a); //push_back addresses of a and b
v.push_back(&b);
...
std::cout << v.at(1)->at(0) //dereference and call at on the inner vec
Note that this can be dangerous if a or b go out of scope before v, as that will leave you with dangling pointers, a mess of undefined behavior and a murder time-consuming bugs.
The basic issue is that push_back copies its parameter to the end of the vector. To modify the object in the vector, you need to get a reference to it. One approach:
std::vector< std::vector<int> > my_vector;
my_vector.reserve(2); // Going over the allocation invalidates references
my_vector.push_back( std::vector<int>() );
std::vector<int> & a = my_vector.back();
my_vector.push_back( std::vector<int>() );
std::vector<int> & b = my_vector.back();
(I changed the name of the variable because using "vector" as a variable name tends to lead to confusion.)
If you can use C++17, there is a way to reduce the lines of code using emplace_back.
If you know the number of vectors ahead of time you can do it like this:
std::vector<std::vector<int>> v(2);
std::vector<int> &a = v[0];
std::vector<int> &b = v[1];
...

C++: How to properly go through vector pointed to

Say that I have a vector, v,
vector <int> v = {0,1,2,...n};
What is the proper way to loop through v in a function taking a pointer to v as an argument? I can see two ways, either dereference the vector using (*) or using the .at() member:
void foo(vector <int>* v)
{
for (auto& el : (*v))
bar(el);
}
or
void foo(vector <int>* v)
{
for (int k = 0; k < n; k++)
bar(v->at(k));
}
Is there any difference between the two? Or is there another, superior, way to do it? It seems to me the second one would dereference the full vector object each iteration to get a single value, which seems like a bit of an over-kill, surely it would be better to only dereference the value at the memory location you want?
Pointer will be dereferenced in both cases. However at performs range checking and throws an exception if it fails so second approach will be slower.
A proper approach may look like this:
void foo(::std::vector<int> & v)
{
for(auto & el: v)
{
bar(el);
}
}
Since your code assumes that pointer is always valid there is not a single reason to use it instead of a reference. See Cpp Core Guidelines.

use function inside of loop which returns vector

I have a function myfun which will return a vector.
vector<double> myfun(const size_t k, const size_t i){
vector<double> v(k);
// do some computation with remaining arguments
return v;
}
Then, I will use it in the loop to update v and use v to get some result.
int main(){
size_t N = 100; // iteration size
size_t n = 10; // size of v
vector<double> result(N);
vector<double> v(n);
for(size_t i = 0; i<N; i++){
v = myfun(n,i); // compute for each iteration
result[i] = compute_some_value(v);
}
}
So, my question is:
Does v actually allocated inside of myfun every time it is called?
If it does, what happens to old v?
Also, is it better to use just use address like void myfun(some_args, vector<double> &v) for output argument v?
Does v actually allocated inside of myfun every time it is called?
Yes
If it does, what happens to old v?
It gets overwritten.
Also, is it better to use just use address like void myfun(some_args, vector &v) for output argument v?
Yes, it's better to pass vector by reference depending on your operations.
You could do it this way
double compute_some_value(vector<double> & v, const size_t i) {
v.clear(); // use if required
// do some computation with remaining arguments and return
}
int main() {
size_t N = 100; // iteration size
size_t n = 10; // size of v
vector<double> result(N), v(n);
for (size_t i = 0; i < N; i++) {
result[i] = compute_some_value(v, i);
}
}
Does v actually allocated inside of myfun every time it is called?
Yes
If it does, what happens to old v?
When v gets out of scope the destructor is called and the object gets destruct. This is why you don't really have to call destructor of a class explicitly.
Also, is it better to use just use address like void myfun(some_args,
vector &v) for output argument v?
It really depends on your use case. If it concerns with memory issues, its better to pass the reference.

Auto vs concrete type when iterating over vector?

The book i am reading offers this example when iterating over a vector
for (auto &e: v) {
cout << e << endl;
}
Suppose v is declared as vector<int> v, in other words, we know that the type of elements inside this collection is int.
Is using auto in any way better or preferred to?
for (int &e: v) {
cout << e << endl;
}
Why?
Yes. auto is preferred. Because if you change the declaration ofv from:
std::vector<int> v; //before
to this:
std::vector<float> v; //after
If you use int & in the for, then you have to change that as well. But with auto, no need to change!
In my opinion, working with auto is more or less like programming to interface. So if you do an operation += in the loop, and you don't really care about the type of the loop variable e as long as the type supports += operation, then auto is the solution:
for(auto & e : v)
{
e += 2;
}
In this example, all you care about that the type of e supports += with int on the right hand side. It will work even for user-defined types, which has defined operator+=(int), or operator+=(T) where T is a type which supports implicit conversion from int . It is as if you're programming to interface:
std::vector<Animal*> animals;
animals.push_back(new Dog());
animals.push_back(new Cat());
animals.push_back(new Horse());
for(size_t i = 0 ; i < animals.size(); ++i)
{
animals[i]->eat(food); //program to interface
}
Of course, you would like to write this loop as:
for(Animal * animal : animals)
{
animal->eat(food); //still program to interface
}
Or simply this:
for(auto animal : animals)
{
animal->eat(food); //still program to interface
}
It is still programming to interface.
But at the same time, the point in #David's comment is worth noting.
On your first example, you have less dependency on what the elements of the vector are.
Suppose that in a month, you require that your vector stores larger integers, so you will have to use an std::vector<int64_t>, or some other, wider type. Now all of the code that iterates over that vector is invalid. You'll have to modify each:
for (int &e: v) {}
For a:
for (int64_t &e: v) {}
That is why it's better to just let auto deduce the internal type. That way you can modify the type stored in your vector for another, compatible one, and all your code will still work.