为什么基于范围的循环不修改容器元素?
Why doesn't range-based for loop modifiy container elements?
我最近观察到修改自动迭代向量中的数据并不能为我产生正确的结果。例如,当我尝试对向量的向量的元素进行排序时,某些元素没有排序,但代码运行成功
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)
.
为什么修改自动迭代数据不是语法错误?
因为它在语法上是可以修改变量的,无论变量是否是引用。 示例:
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
我最近知道,当基于 for 循环的范围内的数据被修改时,结果是未定义的。
你遇到了不正确的知识。在基于 for 循环的范围内修改变量不会产生未定义的结果。
有些操作可能不会在正在迭代的范围上执行,特别是那些使迭代器/对迭代范围元素的引用无效的操作。您可能对此感到困惑。
您展示的程序具有明确定义的行为。但是,您可能打算对矢量元素进行排序,但尚未成功完成。为此,您必须引用向量的元素,而不是复制。这是通过使用引用来实现的:
for( auto &v : arr )
^ this makes the variable a reference
而当我排序为 sort(arr[0].begin(), arr[0].end()) 时,结果是正确的。
下标运算符返回引用。
这里没有未定义的内容,也没有理由出现语法错误。
循环按值迭代外部向量,然后对内部向量的本地副本进行排序。这毫无意义,但并不顽皮。
我最近知道,当基于 for 循环的范围内的数据被修改时,结果是未定义的。
你不能在结构上修改你正在迭代的东西,真的,因为这会破坏迭代。
但这不是你所做的。即使您编写了auto& v : arr
,从而修改了内部向量的值,您仍然没有执行任何破坏外部向量arr
迭代的操作。
不过,不要在循环中写arr.clear()
!
为什么修改自动迭代数据不是语法错误?
即使你的程序有未定义的行为,这从来都不是语法错误,通常甚至不是运行时错误。
但是,如果有一个一揽子规则规定在基于范围的 for 循环中不能执行任何变异操作,请放心,该语言的语义可能会强制要求编译时错误来阻止您这样做(例如您无法构建直接修改const int
的程序)。
我最近才知道,当基于 for 循环的范围内的数据被修改时,结果是未定义的。
你弄错了。如果您修改容器本身(例如向其添加或删除元素),而不是修改它包含的数据,则这是未定义的行为:
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。但是当然,根本不应该编写这样的代码,因为它很容易出错,在这种情况下应该在迭代器范围内进行迭代。
- 如何将字节数组元素替换为修改的十六进制 ASCII 符号?
- C++ std::vector语言 - 如何修改迭代器指定的元素?
- 打印/修改类对象的特定成员变量,其类定义列表 (STL) 包含的元素类型
- 如何修改所有文本元素;Visual Studio c++
- C++ 当容器在使用前被破坏/修改时发出警告(通过引用元素或迭代器使用)
- 如何使用初始化列表循环修改元素
- 为什么基于范围的循环不修改容器元素?
- 通过const_cast修改常量 std::vector 的元素<T>
- 修改 std::D efined 行为的元素?
- 从equal_range查询中筛选和修改 boost::multi_index 中的元素
- 如何转换一个类方法以修改另一个类的私有元素?
- 如何使用用户输入正确修改 2D 数组中的字符数组元素?专门用于电影院座位
- Armadillo C :如何使用来自另一个矩阵的多个元素(特别是在立方体结构中)修改矩阵的多个数组元素
- 如何在不知道大小的情况下编写过程来修改动态数组的元素和大小
- 如何修改 Kadane 算法以找出贡献最大总和的子数组元素?
- 如何在不修改现有函数的情况下反转数组中除第一个和最后一个元素之外的所有元素
- 迭代一个巨大的 std::vector of std::vectors 并修改元素
- C++ unordered_set指针允许修改元素
- 当需要修改元素时,另一种类似集合的数据结构是什么?
- 在std::map中修改元素键的最快方法是什么?