在基于范围的for循环中向该向量添加元素到预分配向量是否合法? [英] Is it legal to add elements to a preallocated vector in a range-based for loop over that vector?

查看:173
本文介绍了在基于范围的for循环中向该向量添加元素到预分配向量是否合法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Visual Studio 2015 Update 1 C ++编译器和此代码片段:

I'm using Visual Studio 2015 Update 1 C++ compiler and this code snippet:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
  vector<int> v{3, 1, 4};

  v.reserve(6);

  for (auto e: v)
    v.push_back(e*e);

  for (auto e: v)
    cout << e << " ";

  return 0;
}

发布版本运行正常,但调试版本生成迭代器不兼容错误消息。为什么?

Release version runs fine, but debug version produces vector iterators incompatible error message. Why is that?

在将其标记为重复的问题之前,请将元素添加到向量在基于范围的循环c ++ 11 ,请阅读我的回答
http://stackoverflow.com / a / 35467831/219153

Before you flag it as a duplicate question to Add elements to a vector during range-based loop c++11, please read my answer http://stackoverflow.com/a/35467831/219153 with arguments to the contrary.

推荐答案

您的代码显示未定义的行为,

Your code exhibits undefined behavior, but it is tricky and tends to only be caught in debug builds.

当您执行 v.push_back 时,所有迭代器如果大小超过容量,则无效。

When you do a v.push_back, all iterators are invalidated if size passes capacity. You avoid this with a reserve.

但是,即使不会导致容量增长,过期迭代器仍然会失效。一般来说,迭代器无效规则不区分迭代器的值将是垃圾/指向不同的对象,并且迭代器的位置不再有效。当发生时,迭代器被简单地认为是无效的。因为结束迭代器不再是结束迭代器(它从指向没有,到几乎每一个实现中的一些东西),标准只是声明它是无效的。

However, even if you don't cause the capacity to grow, the past-the-end iterator is still invalidated. In general, iterator invalidation rules do not distinguish between "the iterator's 'value' would be garbage/refer to a different object" and "the iterator's 'location' is no longer valid". When either occurs, the iterator is simply deemed invalid. As the end iterator is no longer the end iterator (it goes from referring to nothing, to referring to something, in almost every implementation), the standard simply states it is invalidated.

此代码:

for (auto e: v)
  v.push_back(e*e);

大致扩展:

{
  auto && __range = v; 
  for (auto __begin = v.begin(),
    __end = v.end(); 
    __begin != __end;
    ++__begin
  )
  { 
       auto e = *__begin;
       v.push_back(e*e);
  }
}

v.push_back 调用使 __ end 迭代器无效,然后对其进行比较,并且调试生成将未定义的行为正确标记为问题。调试MSVC迭代器对无效规则非常小心。

the v.push_back call invalidates the __end iterator, which is then compared against, and the debug build correctly flags the undefined behavior as a problem. Debug MSVC iterators are pretty careful with invalidation rules.

发布版本没有定义行为,因为向量迭代器基本上是一个指针的薄包装,过去端元素成为在没有容量溢出的推回之后的最后一个元素的指针,它工作。

The release build does undefined behavior, and as the vector iterator is basically a thin wrapper around a pointer, and the pointer to the past-the-end element becomes the pointer to the last element after a push back without a capacity overflow, it "works".

这篇关于在基于范围的for循环中向该向量添加元素到预分配向量是否合法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆