如果双端队列不够大,为什么通过 std::copy 将 std::deque 对象附加到自身成功?

Why is appending std::deque object to itself through std::copy successful if the deque is not large enough?

书说的对,只是看错了一行

正如 明确指出的,以下问题取决于我的误读。

在阅读 Josuttis 的 C++ 标准库(第 2 版) 时,我不知何故确信第 457 页的 coll 被声明为 std::deque (反之声明为std::list!),所以才问这个问题

希望能为广大读者提供思想食粮

原始问题:

在 "The C++ Standard Library (2nd edition)" 的第 456 页,Josuttis 评论说,在您致电

之前
copy(coll.begin(), coll.end(), back_inserter(coll));

在 class std::vectorcoll 上,您必须确保 coll 有足够的 space(在这种情况下,它有一个 capacity 至少是 size 的两倍),否则

the algorithm invalidates the passed source iterators while running.

相反,在第 458 页,他没有针对

的情况说任何类似的话
copy(coll.begin(), coll.end(), front_inserter(coll));

应用于 class std::dequecoll,尽管在第 286 页,有关 std::deque 容器的指定如下:

[...] when elements are inserted at the front or the back. In this case, references and pointers to elements stay valid, but iterators don’t.

因此我怀疑。 (是的,我知道 std::deque 甚至不提供类似 reserve 的成员函数。)

只要我理解了this answer,我的理解是front_inserter(coll)迭代器可以导致指针数组的重新分配(这是实现 std::deque 的合法方式),并且 不能 导致存储 coll 的实际元素的数组重新分配,从而留下 references/pointers 元素 有效,同时使 iterator 无效,其正确行为(我正在考虑如何实现 operator++)依赖于数组指针和指向的数组。

如果这是真的,那么我猜对应于 copy 的参数 coll.begin() 的参数在分配给它的那一刻会失效导致指针数组的重新分配。

本书第455/456页介绍std::back_inserter,第457/458页介绍std::front_insert。每种情况都有一个简短的解释,包括适用容器的列表。每个部分都有一个代码片段作为示例,仅选择 一个 个适用容器来举例说明用法。

对于std::back_inserter,由于选择了容器std::vector,代码片段中的注释提到,为什么需要先在vector中预留足够的space。

对于 std::front_inserter,作者选择了 std::list,而不是 std::dequestd::list 不会在插入时使引用或迭代器失效,因此

copy(coll.begin(), coll.end(), front_inserter(coll));

可以,请参阅当前 C++ 草案的 [list.modifiers]/1

因此,在这两种情况下,作者的代码都没有错误。我想他从来没有打算完全解释复制到容器本身的危险,而是简单地选择了这些案例,因为它允许他编写更短的完整用法示例。

我认为对于 collstd::deque 的情况,这显然是未定义的行为。 std::front_inserter 通过调用 push_front 插入元素(参见 [front.insert.iter.ops]/2), which invalidates all iterators (see [deque.modifiers]/1):

同时std::copy的行为是[alg.copy]/4:

Effects: Copies elements in the range [first, last) into the range [result, result + N) starting from first and proceeding to last. For each non-negative integer n < N, performs *(result + n) = *(first + n).

第一次插入后,first失效,会导致未定义的行为。