std::vector 构造initializer_list的行为不符合预期



以下代码是在 OpenSUSE Tumbleweed 下编译的,带有 GCC 9.2.1 20190903修订版 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;
}

输出为

DEBUG: vector 2 3 4 5 6 0

但我期待

DEBUG: vector 1 2 3 4 5 6

然而,对于其他代码:

#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;
}

输出符合预期:

DEBUG: vector 1 1 2 3 4 5

命令行g++-9 test.cc

我错过了什么吗?这是编译器中的错误吗?

基于范围的 for 循环中变量 d 的值

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

不是向量中的索引。它是向量的当前元素的值

只需使用

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

对于这个载体

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

你得到了预期的结果,因为

datos[datos[1]]等于 1 即等于此元素

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

datos[datos[1]]再次产生相同的元素。

datos[datos[2]]等于 2,依此类推。

例如,如果您将更改矢量,例如

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

然后,您将有未定义的行为,因为datos[datos[2]]尝试访问超出为矢量元素分配的内存的内存。

无需深入细节,此循环

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

实际上相当于以下

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

我错过了什么吗?

您将基于范围的循环与索引混合到矢量中 - 而是选择一种样式。修复了基于范围的 for 循环的示例(允许您直接迭代范围的元素(:

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

手动索引示例:

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

对于基于范围的for循环,该项已经是 int。

正确使用基于范围的for循环

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

或使用传统循环

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

最新更新