【问题标题】:Pushing elements to a vector within a ranged based for loop将元素推送到基于 for 循环的范围内的向量
【发布时间】:2016-01-21 20:23:05
【问题描述】:

有人可以向我解释为什么这个简单的代码:

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v = {0, 1, 2, 3, 4, 5};

    for(auto i: v)
    {
        std::cout << i << ' ';
    }

    std::cout << std::endl;

    for(auto i: v)
    {
        std::cout << i << ' ';
        v.push_back(4);
    }

    std::cout << std::endl;

    for(auto i: v)
    {
        std::cout << i << ' ';
    }
}

此处发布代码:http://cpp.sh/5kxdu

输出:

0 1 2 3 4 5 
0 0 2 3 4 5 
0 1 2 3 4 5 4 4 4 4 4 4 

虽然我期望:

0 1 2 3 4 5 
0 1 2 3 4 5 
0 1 2 3 4 5 4 4 4 4 4 4 

我知道在for 循环期间修改向量是不好的(当我点击这个时只是在尝试其他东西)。在v 声明之后,v.capacity() 返回6,显然,在声明v 之后添加v.reserve(12) 可以解决问题。在push_back 操作期间,肯定有一些与向量重新分配自身以扩展其容量有关。

但我想知道这是否只是一种不确定的行为,我很幸运只有第二个元素是错误的,或者这是否是可预测和可解释的(考虑到 for 循环的工作原理)。

【问题讨论】:

    标签: c++ c++11 vector


    【解决方案1】:

    ranged based for loop 的形式为

    {
        auto && __range = range_expression ; 
        for (auto __begin = begin_expr,
             __end = end_expr; 
             __begin != __end; ++__begin) { 
            range_declaration = *__begin; 
            loop_statement 
        } 
    } 
    

    并在循环开始时设置beginend 迭代器。当您调用push_back 时,它总是使end 迭代器无效,如果size 增长大于capacity,则所有迭代器都将失效。

    因此,使用 push_back 会导致未定义的行为,因为您正在使用不再有效的迭代器。

    【讨论】:

    • 所以输出可能比原来更混乱,对吧?
    • @jpo38 是的。由于它有 UB,它可能会导致守护进程飞出计算机。
    【解决方案2】:

    在第一个push_back 之后,向量重新分配其缓冲区,并且范围 for 循环中的迭代器无效。

    【讨论】:

    • 我会说它可能会重新分配缓冲区。
    • @Slava 因为 OP 说容量是 6,所以保证它会重新分配。
    • @NathanOliver 是的,我错过了有问题的那部分,我今天很马虎:(
    • @Slava for( Slava ) give("Coffe");
    • @Slava 恕我直言,向量要么重新分配其缓冲区,要么分配一个新缓冲区。复数(即缓冲区)我认为这会产生误导,因为向量有一个缓冲区。
    【解决方案3】:

    这是因为 for 循环使用的迭代器在推回期间可能会失效。在底层,vector 使用了一个缓冲区,而 push_back 可以导致数组被重新分配。

    更多参考: http://www.cplusplus.com/forum/general/5189/

    What happens under the hood of vector::push_back memory wise?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-26
      • 2020-06-01
      • 2020-05-03
      • 2016-10-31
      • 1970-01-01
      • 2021-04-08
      相关资源
      最近更新 更多