为什么基于范围的 for 循环不修改容器元素?

Why doesn't range-based for loop modifiy container elements?

我最近观察到在自动迭代向量中修改数据并没有为我产生正确的结果。例如,当我尝试对 vector of vector 的元素进行排序时,某些元素未排序但代码 运行 成功

vector<vector<int> > arr;
arr.push_back({38, 27});
for(auto v : arr)
{
    sort(v.begin(), v.end());
}

以上代码排序后的输出仍然是38、27。而当我排序为 sort(arr[0].begin(), arr[0].end()) 时,结果是正确的。我使用 gcc 编译。

您的 for 循环复制 v,然后对其进行排序。原件未动。你要的是for (auto &v : arr).

I recently came to know that when a data inside range based for loop is modified, the result is undefined.

你完全错了。如果您修改容器本身并对其进行迭代(例如向其添加或删除元素),这就是未定义行为,而不是您修改它包含的数据:

 std::vector<int> v( 10 );
 for( auto i : v ) v.push_back( 10 ); // UB as v is modified, new element inserted to it

对比:

 std::vector<int> v( 10 );
 for( auto &i : v ) i = 123; // totally fine you modify elements inside vector

你的其他问题毫无意义,因为它是基于这个错误的假设。您没有观察到向量变化中的数据的原因是不同的,并且已经回答了。但是,即使您修复代码并使其修改容器数据,它仍然可以。

迂腐的注解:甚至声明修改您迭代的容器是 UB 也太笼统了。例如,您可以在迭代时删除 std::list 中的元素并仍然避免 UB。但是当然根本不应该编写这样的代码,因为它很容易出错,在这种情况下应该在迭代器范围内进行迭代。

这里没有什么是未定义的,没有理由出现语法错误。

您的循环按值 迭代外部向量,然后对内部向量的本地副本进行排序。没意义,但不调皮

I recently came to know that when a data inside range based for loop is modified, the result is undefined.

你不能在结构上修改你正在迭代的东西,没错,因为那会破坏迭代。

但这不是你做的。即使您编写了 auto& v : arr,从而修改了内部向量的值,您仍然没有执行任何会破坏外部向量迭代的操作 arr.

但是不要在循环中写 arr.clear()

Why is modification of auto iterated data not a syntax error?

即使您的程序有未定义的行为,这也绝不是语法错误,通常甚至不是运行时错误。

但是,如果 一条概括性规则,说明在 range-based for 循环中不能执行任何变异操作,请放心,语言的语义可能会强制一个 compile-time 错误来阻止你这样做(比如你不能构建一个直接修改 const int 的程序)。

Why is modification of auto iterated data not a syntax error?

因为修饰变量在语法上是合式的,不管变量是不是引用。示例:

int j = 0
int& i = j; // i refers to j
i = 42; // OK; j is modified


int j = 0
int i = j; // i is a copy of j
i = 42; // OK even though i is not reference
        // j is not modified; only i is

int j = 0
auto i = j; // i is a copy of j
i = 42; // OK; same as above except using auto deduced type
        // j is not modified

std::vector<int> int_vec(10);
for(int i : int_vec)
    i = 42; // OK; same as above except within a loop
            // the vector is not modified

for(auto i : int_vec) // i is a copy
    i = 42; // OK; same as above except using both auto and a loop
            // the vector is not modified

for(auto& i : int_vec) // i is a reference
    i = 42; // OK; elements of the vector are modified

I recently came to know that when a data inside range based for loop is modified, the result is undefined.

您遇到了不正确的知识。在基于 for 循环的范围内修改变量不会产生未定义的结果。

有些操作可能无法对正在迭代的范围执行,特别是那些使迭代器/对迭代范围元素的引用无效的操作。您可能对此感到困惑。

您显示的程序有 well-defined 行为。但是,您可能打算对矢量元素进行排序,但您没有成功完成。为此,您必须引用 向量的元素,而不是进行复制。这是通过使用参考来实现的:

for( auto &v : arr )
          ^ this makes the variable a reference

Whereas when i sort as sort(arr[0].begin(), arr[0].end()), the result is correct.

下标运算符returns一个引用.