繁体   English   中英

iterator和back_insert_iterator有什么区别?

[英]What's the difference between iterator and back_insert_iterator?

如果随机访问迭代器可以用于访问相对于它们指向的元素的任意偏移位置的元素(不知何故像指针),为什么不能在std::copy()等通用算法中使用它们而不是使用back_insert_iterator ,两者之间有什么区别?

std::back_insert_iterator是一种特定输出迭代器,它支持push_back操作。 当您使用operator= 写入它时,它会将值push_backs到底层容器中 - 因此,从这个意义上说,它充当具有push_back成员函数的容器的适配器。

一个例子很容易理解:

std::vector<int> v;

std::back_insert_iterator<std::vector<int>>  it(v);

*it = 10; // it is equivalent to v.push_back(10);
 it = 99; // it is ALSO equivalent to v.push_back(99);

for (auto const & i : v)
    std::cout << i << " " ; //10 99

它输出:

10 99

在线演示

通常的迭代器操作++* it没有影响。

但是你很少直接使用它们(我从未直接使用它直到现在)。 您可以将它们与算法一起使用,例如std::copy在这种情况下,您还可以使用std::back_inserter 函数返回std::back_insert_iterator类型的对象。

//assuming dest is a container which supports push_back!
std::copy(src.begin(), src.end(), std::back_inserter(dest));

您还希望看到以下(适配器)迭代器:

因此,根据容器,您选择适配器迭代器。

请注意,它们都是输出迭代器。

为什么不能在std :: copy()等通用算法中使用它们而不是使用back_insert_iterator。

当然,您可以在std::copy等算法中使用随机访问迭代器(或任何输出迭代器)作为第三个参数,但是假设迭代器引用现有范围 - *it++it是明确定义的你传递的价值。 您传递它们以覆盖范围的现有元素,而std::back_insert_iterator 新元素添加到容器中。

希望有所帮助。

实际上,你可以在std::copy完全使用常规迭代器。

int main() {
    std::vector<int> vec{1, 2, 3, 4};

    std::list<int> list{vec.size()};

    std::copy(vec.begin(), vec.end(), list.begin());

    // list = 1, 2, 3, 4
}

但是,正如您可能注意到的,这意味着:

  • 首先创建len(source range)默认元素
  • 然后将元素从源范围复制到目标范围1 x

这是非常低效的,并且要求元素可以默认构造然后分配给。

相反, back_insert_iterator是一个迭代器,它作为普通容器上的适配器运行。 如果你看一下界面,你会发现它根本不像常规迭代器那样,只要你试图推送一个项目,就会在它嵌入的底层容器引用上调用push_back

int main() {
    std::list<int> list;

    std::back_insert_iterator<std::list<int>> bii(list);

    bii = 1;
    bii = 2;
    bii = 3;
    bii = 4;

    // list = 1, 2, 3, 4

    // note: decltype(*bii) == bii&, so deferencing bii serves no purpose;
    // similarly, ++bi does nothing either; both operations are just defined
    // to mimick a regular operator interface so it can be used in regular
    // algorithms over iterators.
}

因此,这两种方法同样有效,但具有不同的行为:

  • 常规迭代器允许您覆盖现有范围
  • back_insert_iterator允许您追加到现有容器

语义是不同的,选择对手头的任务有意义。

常规迭代器对它们正在使用的容器一无所知,除了它所持有的数据类型。 为了向容器添加元素,让我们说一个向量,需要知道向量中的元素数量。

它们可以,但这样做可能不安全。

我建议阅读赫尔辛基大学对迭代器的精彩介绍

如果你有一个容器的迭代器(正向,双向和随机访问都很好),并且你在STL算法上下文中使用它作为输出迭代器,输出将被写入容器, 迭代器永远不会被比较容器的end() 如果所有写入的元素都适合,那么这很好,但如果没有,输出迭代器将到达end() ,并且取消引用它来写下一个元素将给出未定义的行为。

back_insert_iterator这样的东西专门用作输出迭代器,并且不会以这种方式导致UB,因为它们总是可以插入更多元素。

常规迭代器不会更改序列的大小或结构。 特别是随机访问迭代器只访问特定位置的元素。

std::back_insert_iterator<Cont>是一个trmplate,它建模一个具体的输出迭代器,改变它所引用的每个元素所引用的序列:它为每个写入的元素调用cont.push_back() 由于迭代器不会读取它正在修改的序列,因此添加元素的效果非常好。

暂无
暂无

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

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