【问题标题】:Weird behavior of reference to vector.back() after vector is modified修改矢量后对 vector.back() 的引用的奇怪行为
【发布时间】:2013-12-04 14:15:23
【问题描述】:

让我们从这个 C++ 示例代码开始:

#include <vector>
#include <iostream>

int main()
{
    std::vector<int> vec;
    vec.push_back(0);
    for (int i = 1; i < 5; i++)
    {
        const auto &x = vec.back();
        std::cout << "Before: " << x << ", ";
        vec.push_back(i);
        std::cout << "After: " << x << std::endl;
    }
    return 0;
}

代码用g++ test.cc -std=c++11 -O0编译,结果如下:

Before: 0, After: 0
Before: 1, After: 0  
Before: 2, After: 2
Before: 3, After: 3

我期待第二行输出是

Before: 1, After: 1

因为x 是对向量中的一个项目的引用,不能通过将项目附加到向量来修改它。

但是,我目前还没有阅读反汇编代码或进行任何其他调查。另外我不知道这是否是语言标准中未定义的行为。

我想解释一下。谢谢。

【问题讨论】:

    标签: c++ c++11 vector reference


    【解决方案1】:

    push_back 会导致重新分配,如果我们查看draft C++ standard 部分23.3.6.5 向量修饰符 说:

    void push_back(const T& x);

    void push_back(T&& x);

    备注:如果新容量大于旧容量,则会导致重新分配。 如果发生没有重新分配,则插入点之前的所有迭代器和引用仍然有效

    我们可以看到back 为我们提供了一个引用,因此如果有重新分配,它将不再是有效

    【讨论】:

      【解决方案2】:

      vector 迭代器(以及之前对元素的引用)可能在向量被修改后失效。使用它们是不安全的。

      【讨论】:

      • 抱歉,与迭代器无关。
      • @starrify:尝试获取副本,而不是引用 back 后面的值。
      • @KirilKirov 是的,这也是我的怀疑,我想确保这是问题所在(通过引用标准或阅读生成的汇编代码或其他)
      • @BenjaminBannier 那么这就是我用来避免这个问题的方式。在实际代码中(我上面提供的代码只是一个示例)向量中的项目是大小可能很大的结构,这就是我选择引用而不是值复制的原因。
      • @starrify 那么您可能希望避免重新分配开销,并且您应该相应地调整数组大小。如果你事先做一个vec.reserve(100),这个问题应该会消失,只要你保持在 100 个元素以内。
      猜你喜欢
      • 2013-08-15
      • 1970-01-01
      • 2020-10-07
      • 1970-01-01
      • 2017-05-23
      • 1970-01-01
      • 1970-01-01
      • 2022-01-24
      • 1970-01-01
      相关资源
      最近更新 更多