【问题标题】:copy algorithm with back_inserter使用 back_inserter 复制算法
【发布时间】:2013-06-14 08:28:21
【问题描述】:

我不明白为什么这段代码是准确的

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

coll.end() 表示向量的结束。在我 push_back 之后(如back_insert_iterator 所做的那样)coll.end() 返回的内容与之前的内容相同还是有所不同?是否有多个终止迭代器?为什么即使添加了新内容,end() 也可以用作容器的结尾?

此外,您不能将代码应用于列表容器 - 它会卡住。这很重要,因为在向量 push_back 的情况下,在重新分配数据后(当 size()==capacity()push_back() 调用时)迭代器会变得不可靠,而在 list 的情况下则不然。比为什么代码挂起列表?

编辑:(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);
}

【问题讨论】:

    标签: c++ stl-algorithm


    【解决方案1】:

    coll.end() 被称为 before 复制和反向插入开始,所以本质上代码是一样的

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

    意思是,copy 不会重新评估coll.end(),所以它不会注意到/打扰它正在插入同一个向量,并且曾经是向量的结尾不是第一个之后的结尾插入。

    相同的算法不会编译列表,因为std::list 没有reserve 方法。然而,没有reserve 它应该适用于lists,因为std::list::push_back 不会使迭代器无效。 你是对的,std::vector::push_back 在发生重新分配时会使迭代器无效,因此执行reserve 调用非常重要,因为它确保不需要重新分配。

    【讨论】:

    • 我知道列表中没有reserve()。我已经尝试了列表的代码。程序进入无限循环。
    • 您能否向我们展示您用来测试列表中的代码的 [SSCCE](http:/sscce.org)?
    【解决方案2】:

    用于确定要复制的内容的 begin()end() 指针/迭代器在调用函数时被评估一次。所以基本上std::copy() 将增加它的游标迭代器,最终将达到end(),因为vector&lt;T&gt;::const_iterator 只是一个老式数组上的一个花哨的T* 指针。

    正如您正确提到的,如果 push_back 使 vector 重新分配并将数据移动到内存中的其他位置,那么复制的下一个元素将具有错误的源地址,这很可能以分段结束故障。

    对于一个列表,它永远不会终止,因为end() 是一个哨兵/保护指针,您只能通过增加列表最后一个元素的迭代器来达到end()。所以end()的地址本身永远不会改变,但是因为你不断地在链表末尾添加一个元素,你永远不会到达最后一个元素,所以std::copy()永远无法获得指向end()的指针。有点像追尾巴的狗。

    通过插图和图表更容易理解,阅读双向链表和哨点节点,这一切都有意义。

    【讨论】:

      猜你喜欢
      • 2017-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-01
      • 2021-11-23
      • 2012-06-12
      • 2013-08-28
      • 2010-10-28
      相关资源
      最近更新 更多