c++ - 使用 copy 和 back_inserter 将 vector 附加到自身时的错误结果

标签 c++ stl iterator undefined-behavior stl-algorithm

<分区>

灵感来自 this question , 询问如何将 vector 附加到自身,我的第一个想法如下(是的,我意识到 insert 现在是更好的选择):

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

int main() {
    std::vector<int> vec {1, 2, 3};
    std::copy (std::begin (vec), std::end (vec), std::back_inserter (vec));

    for (const auto &v : vec)
        std::cout << v << ' ';
}

然而,这打印:

1 2 3 1 * 3

每次运行程序时,* 都是不同的数字。只有 2 被替换的事实很奇怪,如果真的有解释,我很想听听。继续,如果我附加到不同的 vector (原始 vector 的拷贝),它会正确输出。如果我在 copy 之前添加以下行,它也会正确输出:

vec.reserve (2 * vec.size());

我的印象是 std::back_inserter 是一种将元素添加到容器末尾的安全方法,尽管事先没有保留内存。如果我的理解是正确的,复制行有什么问题?

我认为这与编译器无关,但我使用的是 GCC 4.7.1。

最佳答案

std::back_inserter创建一个插入迭代器,将元素插入到容器中。每次取消引用此迭代器时,它都会调用 push_back在容器上将新元素附加到容器。

对于 std::vector容器,调用 push_back其中 v.size() == v.capacity()将导致重新分配:创建一个新数组来存储 vector 的内容,将其当前内容复制到新数组中,并销毁旧数组。此时 vector 中的任何迭代器都无效,这意味着它们不能再使用。

在您的程序中,这包括 begin(vec) 定义的输入范围和 end(vec)从中copy算法正在复制。该算法继续使用这些迭代器,即使它们已失效,因此您的程序表现出未定义的行为。


即使你的容器有足够的容量,它的行为仍然是未定义的:规范指出,在插入时,“如果没有发生重新分配,插入点之前的所有迭代器和引用仍然有效”(C++11 § 23.3.6.5/1)。

调用push_back相当于在最后插入,所以你传递给 std::end(vec) 的结束迭代器( std::copy )在一次调用 push_back 后失效.如果输入范围不为空,则程序会出现未定义的行为。


请注意,如果您使用 std::deque<int>,您的程序的行为将被明确定义或 std::list<int> ,因为当追加元素时,这些容器都不会使迭代器无效。

关于c++ - 使用 copy 和 back_inserter 将 vector 附加到自身时的错误结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11511510/

相关文章:

multithreading - 在确定性多线程应用程序中使用伪随机数引擎?

c++ - random_shuffle 每次都会产生相同的结果

c++ - std::vector 中非整数元素的总和

c++ - 用于保存不同元素的 2 个 vector 的单个迭代器 (c++)

c++ - STL 映射与 vector 的迭代器访问性能?

c++ - Boost Asio 始终返回 0.0.0.0 IP

c++ - OpenSSL DER ECDSA 编码错误

android - 无法找到 android NDK 堆栈跟踪

c++ - 如何计算数组中出现的次数?

c++ - 列表迭代器不可递增