简体   繁体   English

使用back_inserter复制算法

[英]copy algorithm with back_inserter

I do not understand why this code is accurate 我不明白为什么这段代码是准确的

vector<int> coll;
coll.reserve(2*coll.size());
copy (
  coll.begin(), coll.end(),    // zrodlo
  back_inserter(coll)          // przeznaczenie
);

coll.end() represents the end of vector. coll.end()表示向量的结尾。 After I push_back anything (as back_insert_iterator does) what coll.end() returns is the same what was before or something different? 在我coll.end()回任何事情后(如back_insert_iterator那样), coll.end()返回的内容与之前的相同或不同之处是什么? Are there more than one terminating iterator? 是否有多个终止迭代器? Why end() can be use as an end of container even when new content is added? 为什么end()可以用作容器的末尾,即使添加了新内容?

Moreover, you cannot apply the code to list container - it gets stuck. 此外,您无法将代码应用于列表容器 - 它会卡住。 That is important because in case of vector push_back makes iterators unreliable after reallocating data (when size()==capacity() and push_back() called) whereas in case of list that's not the case. 这很重要,因为在向量的情况下,push_back使得迭代器在重新分配数据后不可靠(当调用size()==capacity()push_back() ),而在列表的情况下则不是这样。 Than why the code hangs for list? 为什么代码挂起列表?

Edit: (sscce) 编辑:(sscce)

#include <iostream>
#include <list>
#include <algorithm>
using namespace std;

template <class T>
inline void PRINT_ELEMENTS (const T& coll, const char* optcstr="")
{
    typename T::const_iterator pos;

    std::cout << optcstr;
    for (pos=coll.begin(); pos!=coll.end(); ++pos) {
        std::cout << *pos << ' ';
    }
    std::cout << std::endl;
}

int main(){
  list<int> coll;

  list<int>::iterator end = coll.end();
  copy (
    coll.begin(), coll.end(),    // zrodlo
    back_inserter(coll)          // przeznaczenie
    );
  cout << *end << endl;
  PRINT_ELEMENTS(coll);
}

coll.end() is called before the copying and back insertion begins, so essentially the code is the same as 在复制和后退插入开始之前调用coll.end() ,因此基本上代码与

coll.reserve(2*coll.size());
auto oldEnd = coll.end();
copy (coll.begin(), oldEnd, back_inserter(coll) ); 

meaning, copy will not re-evaluate coll.end() , so it will not notice/bother that it is inserting into the same vector, and that what once was the end of the vector is not the end after the first insertions. 意思是, copy不会重新评估coll.end() ,因此它不会注意/打扰它插入到同一个向量中,并且曾经是向量的结尾不是第一次插入后的结束。

The same algorithm will not compile for lists, because std::list has no reserve method. 相同的算法不会为列表编译 ,因为std::list没有reserve方法。 However, without reserve it should work for list s, since std::list::push_back does not invalidate iterators. 但是,没有reserve它应该适用于list s,因为std::list::push_back不会使迭代器无效。 You are right that std::vector::push_back invalidates iterators when reallocation occurs, so it's very important to do the reserve call, because it makes sure no reallocation is needed. 你是对的, std::vector::push_back在重新分配时会使迭代器失效,所以进行reserve调用非常重要,因为它确保不需要重新分配。

the begin() and end() pointers/iterators used to determine what is to be copied are evaluated once when the function is called. 在调用函数时,用于确定要复制的内容的begin()end()指针/迭代器将被计算一次。 So essentially std::copy() will increment it's cursor iterator which will eventually reach end() , because vector<T>::const_iterator is just a fancy T* pointer on an old school array. 所以基本上std::copy()会增加它的光标迭代器,它最终会到达end() ,因为vector<T>::const_iterator只是旧学校数组上的一个奇特的T*指针。

As you correctly mentionned, if a push_back makes the vector reallocate and move the data somewhere else in memory, then the next element copied will have a wrong address for source, which is likely to end up with a segmentaion fault. 正如您正确提到的,如果push_back使vector重新分配并将数据移动到内存中的其他位置,则复制的下一个元素将具有错误的源地址,这可能最终导致段故障。

For a list, it can never terminate because end() is a sentinel/guard pointer, and you can only reach end() by incrementing the iterator on the last element of the list. 对于列表,它永远不会终止,因为end()是一个sentinel / guard指针,并且只能通过递增列表最后一个元素上的迭代器来到达end() So the address of end() itself never changes, but because you are constantly adding an element at the end of the list, you will never reach the last element, so std::copy() can never obtain a pointer to end() . 所以end()的地址本身永远不会改变,但是因为你不断在列表的末尾添加一个元素,你永远不会到达最后一个元素,所以std::copy()永远不会获得指向end()的指针。 Kind of like a dog chasing it's tail. 有点像狗追逐它的尾巴。

It's easier to understand with illustrations and diagrams, read-up on doubly linked list and sentinel nodes, it will all make sense. 通过插图和图表更容易理解,在双向链表和前哨节点上进行读取,这一切都有意义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM