使用copy和back_inserter将向量附加到自身时,结果错误 [英] Wrong results when appending vector to itself using copy and back_inserter

查看:198
本文介绍了使用copy和back_inserter将向量附加到自身时,结果错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

受到此问题的启发,询问如何向自己添加一个向量,我的第一个想法是以下(是的,我意识到 insert 现在是一个更好的选择):

Inspired by this question, asking how to append a vector to itself, my first thought was the following (and yes, I realize insert is a better option now):

#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被替换是奇怪的,如果实际上有一个解释,我有兴趣听到它。继续,如果我附加到一个不同的矢量(原件的副本),它输出正确。如果我在 copy 之前添加以下行,它也会正确输出:

The * is a different number every time the program is run. The fact that it's only the 2 being replaced is peculiar, and if there actually is an explanation for that, I'd be interested to hear it. Continuing, if I append to a different vector (a copy of the original), it outputs correctly. It also outputs correctly if I add the following line before the copy one:

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

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

I was under the impression std::back_inserter was a safe way to add elements onto the end of a container, despite not reserving memory beforehand. If my understanding is correct, what's wrong with the copying line?

我认为它与编译器无关,但我使用GCC 4.7.1。 p>

I assume it's nothing to do with the compiler, but I'm using GCC 4.7.1.

推荐答案

std :: back_inserter 创建一个插入迭代器, 。每当这个迭代器被解引用时,它会在容器上调用 push_back ,以便为容器添加一个新的元素。

std::back_inserter creates an inserting iterator that inserts elements into a container. Each time this iterator is dereferenced, it calls push_back on the container to append a new element to the container.

对于 std :: vector 容器,调用 push_back 其中 v.size == v.capacity()将导致一个重新分配:创建一个新的数组来存储向量的内容,其当前内容被复制到新数组,并且旧数组被破坏。

For a std::vector container, a call to push_back where v.size() == v.capacity() will result in a reallocation: a new array is created to store the contents of the vector, its current contents are copied into the new array, and the old array is destroyed. Any iterators into the vector at this time are invalidated, meaning they can no longer be used.

在程序中,这包括输入范围由 begin(vec) end(vec)定义, c $ c>算法是复制。该算法继续使用这些迭代器,即使它们无效,因此您的程序显示未定义的行为。

In your program, this includes the input range defined by begin(vec) and end(vec) from which the copy algorithm is copying. The algorithm continues to use these iterators, even though they are invalidated, thus your program exhibits undefined behavior.

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

Even if your container had sufficient capacity, its behavior would still be undefined: the specification states that, upon insertion, "if no reallocation happens, all the iterators and references before the insertion point remain valid" (C++11 §23.3.6.5/1).

调用 push_back 等效于在结尾处插入,因此结束迭代器( > std :: copy 时无效的传递到> std :: end(vec) push_back 。如果输入范围不为空,程序因此显示未定义的行为。

The call to push_back is equivalent to insertion at the end, so the end iterator (std::end(vec)) that you passed into std::copy is invalidated after a single call to push_back. If the input range is nonempty, the program therefore exhibits undefined behavior.

注意,程序的行为会很好如果您使用 std :: deque< int> std :: list< int> 当附加元素时,这些容器都不会使迭代器无效。

Note that the behavior of your program would be well-defined if you used a std::deque<int> or a std::list<int>, because neither of those containers invalidates iterators when elements are appended.

这篇关于使用copy和back_inserter将向量附加到自身时,结果错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆