我最近发现修改自动迭代向量中的数据不会为我产生正确的结果。例如,当我尝试对vector的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进行编译。
答案 0 :(得分:10)
您的for循环复制v,然后对其进行排序。原稿未触碰。您想要的是for (auto &v : arr)
。
答案 1 :(得分:2)
我最近才知道,当修改基于for循环的范围内的数据时,结果是不确定的。
您完全错了。如果您修改容器本身进行迭代(例如向其添加或删除元素),而不是修改容器中包含的数据,则这是未定义行为:
std::vector<int> v( 10 );
for( auto i : v ) v.push_back( 10 ); // UB as v is modified, new element inserted to it
vs:
std::vector<int> v( 10 );
for( auto &i : v ) i = 123; // totally fine you modify elements inside vector
您的问题的其余部分是毫无意义的,因为它基于此错误的假设。您没有观察到向量变化内的数据的原因有所不同,并且已经得到解决。但是,即使您修复了代码并使其修改了容器数据,也还是可以的。
需要注意的一点:即使声明修改您遍历的容器是UB,也太笼统了。例如,您可以在std::list
中进行迭代时删除元素,但仍避免使用UB。但是当然不应该编写这样的代码,因为这样很容易出错,在这种情况下应该在迭代器范围内进行迭代。
答案 2 :(得分:2)
这里没有什么是未定义的,没有理由出现语法错误。
您的循环按值迭代外部向量 ,然后对内部向量的本地副本进行排序。这没有意义,但这不是顽皮的。
我最近才知道,当修改基于for循环的范围内的数据时,结果是不确定的。
您不能在结构上修改要迭代的内容,因为这样做会破坏迭代。
但这不是您所做的。即使您编写了auto& v : arr
,从而修改了内部向量的值,您仍然没有执行任何操作来中断外部向量arr
的迭代。
不过,请不要在循环内写入arr.clear()
!
为什么修改自动迭代数据不是语法错误?
即使您的程序具有未定义的行为,也绝不会出现语法错误,甚至通常不会出现运行时错误。
但是,如果有一条笼统的规则指出在基于范围的for循环内无法执行任何变异操作,请放心,该语言的语义可能会导致编译时错误,阻止您执行此操作(例如无法构建直接修改const int
的程序)。
答案 3 :(得分:2)
为什么修改自动迭代数据不是语法错误?
因为修改后的变量在语法上结构合理,无论变量是否为引用。示例:
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( auto &v : arr )
^ this makes the variable a reference
当我以sort(arr [0] .begin(),arr [0] .end())进行排序时,结果是正确的。
下标运算符返回引用。