简体   繁体   中英

std::vector constructed with initializer_list not behaving as expected

The following code is compiled under OpenSUSE Tumbleweed with GCC 9.2.1 20190903 revision 275330

#include <vector>
#include <iostream>

int main()
{
    std::vector<double> datos = {1, 2, 3, 4, 5, 6};

    std::cout << "DEBUG: vector ";
    for (auto d : datos)
        std::cout << datos[d] << ' ';
    std::cout << std::endl;
}

The output is

DEBUG: vector 2 3 4 5 6 0

But I was expecting

DEBUG: vector 1 2 3 4 5 6

Yet for this other code:

#include <vector>
#include <iostream>

int main()
{
    std::vector<double> datos = {1, 1, 2, 3, 4, 5};

    std::cout << "DEBUG: vector ";
    for (auto d : datos)
        std::cout << datos[d] << ' ';
    std::cout << std::endl;
}

The output is as expected:

DEBUG: vector 1 1 2 3 4 5

Command line is g++-9 test.cc

Am I missing something? Is this a bug in the compiler?

The value of the variable d in the range-based for loop

for (auto d : datos)
        std::cout << datos[d] << ' ';

is not an index in the vector. It is a value of the current element of the vector

Just use

for (auto d : datos)
        std::cout << d << ' ';

For this vector

std::vector<double> datos = {1, 1, 2, 3, 4, 5};

you got the expected result because

datos[datos[1]] is equal to 1 that is it is equal to this element

std::vector<double> datos = {1, 1, 2, 3, 4, 5};
                               ^^^

datos[datos[1]] again yields the same element.

datos[datos[2]] is equal to 2 and so on.

If you for example will change the vector like

std::vector<double> datos = { 5 };

then you will have undefined behavior because datos[datos[2]] tries to access memory beyond the allocated memory for the vector's elements.

Without deeping in details this loop

for (auto d : datos)
    std::cout << d << ' ';

in fact is equivalent to the following

for ( auto first = std::begin( datos ); first != std::end( datos ); ++first )
{
    auto d = *first;
    std::cout << d << ' ';
}

Am I missing something?

You mixed range based for loops with indexing into a vector - instead, pick one style. Fixed example with range-based for loop (which allows you to directly iterate over the elements of a range):

for (auto d : datos)
    std::cout << d << ' ';

Example with manual indices:

for (std::size_t i = 0; i < datos.size(); ++i)
    std::cout << datos[i] << ' ';

For a range-based for loop, the item is already an int.

Either use range-based for loop correctly

for (auto d : datos)
    std::cout << d << ' ';

Or use traditional loop

for (size_t d = 0; d < datos.size(); ++d)
    std::cout << datos[d] << ' ';

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM