【问题标题】:Unexpected behavior using iterators with nested vectors使用带有嵌套向量的迭代器的意外行为
【发布时间】:2012-05-09 06:29:47
【问题描述】:

这个示例程序获取一个指向另一个向量中包含的向量元素的迭代器。我将另一个元素添加到包含向量中,然后打印出之前获得的迭代器的值:

#include <vector>
#include <iostream>

int main(int argc, char const *argv[])
{
    std::vector<std::vector<int> > foo(3, std::vector<int>(3, 1));
    std::vector<int>::iterator foo_it = foo[0].begin();
    std::cout << "*foo_it: " << *foo_it << std::endl;
    foo.push_back(std::vector<int>(3, 2));
    std::cout << "*foo_it: " << *foo_it << std::endl;
    return 0;
}

由于与foo_it 对应的向量尚未修改,我希望迭代器仍然有效。但是,当我运行此代码时,我得到以下输出(也在 ideone 上):

*foo_it: 1
*foo_it: 0

作为参考,我使用 g++ 版本 4.2 和 4.6 以及 clang 3.1 得到了这个结果。但是,我使用 -std=c++0x (ideone link) 和 clang 在同时使用 -std=c++0x-stdlib=libc++ 时获得了 g++ 的预期输出。

我是否在这里调用了一些未定义的行为?如果是这样,这是现在定义的行为 C++11 吗?或者这只是一个编译器/标准库错误?

编辑我现在可以看到,在 C++03 中,迭代器无效,因为向量的元素在重新分配时被复制。但是我仍然想知道这在 C++11 中是否有效(即向量的元素是否保证被移动而不是复制,并且移动向量不会使其迭代器无效)。

【问题讨论】:

    标签: c++ vector iterator c++11


    【解决方案1】:

    push_back 使迭代器无效,就这么简单。

    std::vector<int>::iterator foo_it = foo[0].begin();
    foo.push_back(std::vector<int>(3, 2));
    

    此后,foo_ti 不再有效。任何 insert/push_back 都有可能在内部重新分配向量。

    【讨论】:

    • 还会使任何指向向量元素的指针或引用无效,例如由operator[] 获得的那些。
    • 他没有在 vector 上调用 push_back,他从中获取了迭代器。
    • @LuchianGrigore 他打电话给foo[0].begin(),然后是push_backfoo,而不是foo[0]
    • @SethCarnegie:外部向量的push_back 被允许复制它的内部元素,并且复制的向量的迭代器与源向量的迭代器不匹配。 (然后,在外部向量重新分配后,原始向量被销毁,这使迭代器无效)它适用于-std=c++0x,因为内部向量被移动而不是复制。
    • @DavidBrown:考虑到 std::vector<:unique_ptr>> 是可以的,如果 C++11 承认任何其他行为(因为你 无法复制 unique_ptr s)
    【解决方案2】:

    由于foo_it对应的向量没有被修改

    错了。 push_back 破坏了与foo_it 对应的向量。当foo[0] 被销毁时,foo_it 变得无效。

    【讨论】:

      【解决方案3】:

      我猜误解是vector>是一个指针向量,当重新分配外部指针时,指向内部指针的指针仍然有效,这对于**int是正确的。但相反,重新分配向量也会重新分配所有内部向量,这也会使内部迭代器无效。

      【讨论】:

      • 并非总是如此。 (实际上在 C++11 中总是错误的)
      • 我通过打印出两个值的地址进行了测试,它们是相同的。这意味着来自内部向量的数据已被重新分配,对吧?
      • 这取决于你在说什么地址。但问题是,在 C++11 中,std::vector 必须尽可能移动它的内部(而不是复制),并且移动操作不会使迭代器无效或导致重新分配。
      • @Billy - 什么?如果一个对象被移动到一个新的地方,那么原始的迭代器现在肯定是无效的。
      • @Bo:迭代器只是指向移动的项目。 (以向量为例,移动操作将内存指针从一个向量对象移动到另一个,但迭代器是指向该内存块的指针——并且该块根本没有被移动修改)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-03-25
      • 2012-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多