书是对的,我只是看错了一行。
正如 answer by @uneven_mark 明确指出的,以下问题取决于我的误读。
在阅读 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));
在 std::vector
类的 coll
上,您必须确保 coll
有足够的空间(在这种情况下,它有容量
至少是其大小
的两倍),否则
the algorithm invalidates the passed source iterators while running.
相反,在第 458 页,他没有说任何类似的情况
copy(coll.begin(), coll.end(), front_inserter(coll));
应用于 std::deque
类的 coll
,尽管在第 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
实际元素的数组的重新分配,从而留下引用/指向元素的指针有效,同时使迭代器
无效,其正确行为(我正在考虑如何实现operator++
)依赖于指针数组和指向数组。
如果这是真的,那么我猜对应于 copy
的参数 coll.begin()
的参数在分配给它的那一刻会失效导致指针数组的重新分配。
最佳答案
本书第455/456页介绍了std::back_inserter
,第457/458页介绍了std::front_insert
。每种情况都有一个简短的解释,包括适用容器的列表。每个部分都有一个代码片段作为示例,仅选择一个适用的容器来举例说明用法。
对于std::back_inserter
,由于选择了容器std::vector
,并且代码片段中的注释提到,为什么需要先在其中预留足够的空间 vector 。
对于 std::front_inserter
,作者选择了 std::list
,而不是 std::deque
。 std::list
不会在插入时使引用或迭代器无效,因此
copy(coll.begin(), coll.end(), front_inserter(coll));
很好,请参阅当前 C++ 草案的 [list.modifiers]/1。
因此,在这两种情况下,作者的代码都没有错误。我想他从来没有打算完全解释复制到容器本身的危险,而是简单地选择了这些案例,因为它允许他编写更短的完整用法示例。
我认为对于 coll
是 std::deque
的情况,这显然是未定义的行为。 std::front_inserter
通过调用 push_front
(见 [front.insert.iter.ops]/2 )插入元素,这使所有迭代器无效(见 [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
失效,会导致未定义的行为。
关于c++ - 如果双端队列不够大,为什么通过 std::copy 成功将 std::deque 对象附加到自身?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57646965/