【问题标题】:Range-based for loop and std::vector.push_back() crashing the program基于范围的 for 循环和 std::vector.push_back() 使程序崩溃
【发布时间】:2017-02-24 21:06:49
【问题描述】:
#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec;
    for (int i = 0; i < 42; ++i) {
        vec.push_back(i);
        vec.push_back(-i);
    }
    for (int x: vec) {
        for (int y: vec) {
            vec.push_back(x + y);
        }
    }
    for (int x: vec) {
        std::cout << x << "\n";
    }
}

是什么导致此代码崩溃?我尝试使用 -fsanitize=address 编译它,得到==9347==ERROR: AddressSanitizer: heap-use-after-free on address 0x61500000fdb4 at pc 0x00010a4f1043 bp 0x7fff55710b70 sp 0x7fff55710b68。当我的计算机上的 x == 0 和 y == 22 时,它在 vec.push_back(x + y) 失败。

【问题讨论】:

    标签: c++ c++11


    【解决方案1】:

    来自std::vector::push_back:

    如果新的 size() 大于 capacity() 则所有迭代器和引用(包括过去的迭代器)都将失效。否则只有过去的迭代器无效。

    基于范围的 for 循环在内部使用迭代器。使用push_back 可能会导致这些迭代器失效。

    编辑:请注意,当 y == 22 您将第 65 个元素插入向量中时。容量可能是 64。许多实现将容量增加了 2 的幂(每次都加倍)。

    【讨论】:

    • 执行 push_back 是 UB 在任何循环范围内还是在循环嵌套范围内? (你的回答让我相信“任何循环范围”,但这将是一个陷阱)
    • @user 您不能使用基于范围的 for 循环使迭代器对您正在迭代的向量无效。无效的规则非常明确。例如,您可以在循环中使用push_back,前提是您确定size() 永远不会超过capacity()(例如,通过使用reserve() 来提前充分增加容量)。有关详细的失效规则,请参阅每个 std::vector 的方法页面。是的,这是一个很大的陷阱!
    • 感谢您的精确
    • @user 我想澄清一下,这个问题并不是std::vector 独有的。这是许多容器面临的问题。例如std::deque::erase 或std::unordered_map::insert 可能会使迭代器无效。
    • @FrançoisAndrieux:您可以查看其他相关帖子:stackoverflow.com/questions/48518970/…
    【解决方案2】:

    一旦您为此调用 std::vector::push_back 或大多数 non-const 函数,迭代器就会失效(当新大小超过向量的当前容量时,会导致内部重新分配内存)

    您可以找到一些关于标准容器或迭代器一般如何工作的很好的参考资料。我希望这能让你开始!

    【讨论】:

    • 有一些非常量方法永远不会使迭代器无效。例如std::vector::pop_back 或std::vector::back。
    • @FrançoisAndrieux 或 std::vector::data 。在我看来,这是一个很好的经验法则。大多数非常量方法,除了直接引用数据的方法。
    猜你喜欢
    • 1970-01-01
    • 2016-10-31
    • 2011-10-21
    • 1970-01-01
    • 2014-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多