Why does this code write an undefined number of seemingly uninitialized integers?
#include <iostream>
#include <vector>
using namespace std;
int main()
{
for (int i : vector<vector<int>>{{77, 777, 7777}}[0])
cout << i << ' ';
}
I expected the output to be 77 777 7777
.
Is this code supposed to be undefined?
vector<vector<int>>{{77, 777, 7777}}
is a temporary and then using vector<vector<int>>{{77, 777, 7777}}[0]
in ranged-for will be an undefined behaviour.
You should create a variable first, like
#include <iostream>
#include <vector>
using namespace std;
int main()
{
auto v = vector<vector<int>>{{77, 777, 7777}};
for(int i: v[0])
cout << i << ' ';
}
Also If you use Clang 10.0.0 it gives warning about this behaviour.
warning: object backing the pointer will be destroyed at the end of the full-expression [-Wdangling-gsl] vector>{{77, 777, 7777}}[0]
This is because the the vector you are iterating over will be destroyed before entering the loop.
This is what typically happens:
auto&& range = vector<vector<int>>{{77, 777, 7777}}[0];
auto&& first = std::begin(range);
auto&& last = std::end(range);
for(; first != last; ++first)
{
int i = *first;
// the rest of the loop
}
The problems start at the first line because it's evaluated as follows:
Firstly construct the vector of vectors with the given arguments and that vector becomes a temporary because it has no names.
Then the range reference is bound to the subscripted vector which will only be valid as long as the vector that contains it is valid.
Once the semicolon is reached the temporary vector is destroyed and in its destructor it will destroy and deallocate any stored vectors which includes the subscripted one.
You end up with a reference to a destroyed vector which will be iterated over.
To avoid this problem there are two solutions:
Declare the vector before the loop so it lasts until its scope ends which includes the loop.
C++20 comes with an init statement which is provided to solve these problems and is better than the first approach if you want the vector to be destroyed after the loop immediately:
for (vector<vector<int>> vec{{77, 777, 7777}}; int i : vec[0])
{
}
vector<vector<int>>{{77, 777, 7777}}[0]
I expect that this is dangling.
Though the definition of a ranged-for assures that the RHS of the colon remains "alive" for the duration, you're still subscripting a temporary. Only the result of the subscript is kept, but that result is a reference, and the actual vector cannot survive past the full-expression in which it's declared. That does not describe the whole loop.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With