std::insert_iterator 和迭代器失效

发布于 2025-01-02 17:39:34 字数 1553 浏览 0 评论 0原文

我尝试编写一个通用的、就地的 intersperse 函数。该函数应将给定元素分散到元素序列中。

#include <vector>
#include <list>
#include <algorithm>
#include <iostream>

template<typename ForwardIterator, typename InserterFunc>
void intersperse(ForwardIterator begin, ForwardIterator end, InserterFunc ins, 
                 // we cannot use rvalue references here, 
                 // maybe taking by value and letting users feed in std::ref would be smarter
                 const ForwardIterator::value_type& elem) {
  if(begin == end) return;
  while(++begin != end) {
    // bugfix would be something like:
    // begin = (ins(begin) = elem); // insert_iterator is convertible to a normal iterator
    // or
    // begin = (ins(begin) = elem).iterator(); // get the iterator to the last inserted element

    // begin now points to the inserted element and we need to
    // increment the iterator once again, which is safe
    // ++begin;
    ins(begin) = elem;
  }
}

int main()
{
  typedef std::list<int> container;
  // as expected tumbles, falls over and goes up in flames with:
  // typedef std::vector<int> container;
  typedef container::iterator iterator;
  container v{1,2,3,4};

  intersperse(v.begin(), v.end(), 
              [&v](iterator it) { return std::inserter(v, it); },
              23);
  for(auto x : v)
    std::cout << x << std::endl;
  return 0;
}

该示例仅适用于不会使其自身失效的容器 插入时的迭代器。我应该简单地摆脱迭代器并 接受一个容器作为参数还是我错过了一些东西 insert_iterator 使得这种用法成为可能?

I tried writing a generic, in place, intersperse function. The function should intersperse a given element into a sequence of elements.

#include <vector>
#include <list>
#include <algorithm>
#include <iostream>

template<typename ForwardIterator, typename InserterFunc>
void intersperse(ForwardIterator begin, ForwardIterator end, InserterFunc ins, 
                 // we cannot use rvalue references here, 
                 // maybe taking by value and letting users feed in std::ref would be smarter
                 const ForwardIterator::value_type& elem) {
  if(begin == end) return;
  while(++begin != end) {
    // bugfix would be something like:
    // begin = (ins(begin) = elem); // insert_iterator is convertible to a normal iterator
    // or
    // begin = (ins(begin) = elem).iterator(); // get the iterator to the last inserted element

    // begin now points to the inserted element and we need to
    // increment the iterator once again, which is safe
    // ++begin;
    ins(begin) = elem;
  }
}

int main()
{
  typedef std::list<int> container;
  // as expected tumbles, falls over and goes up in flames with:
  // typedef std::vector<int> container;
  typedef container::iterator iterator;
  container v{1,2,3,4};

  intersperse(v.begin(), v.end(), 
              [&v](iterator it) { return std::inserter(v, it); },
              23);
  for(auto x : v)
    std::cout << x << std::endl;
  return 0;
}

The example works only for containers that do not invalidate their
iterators on insertion. Should I simply get rid of the iterators and
accept a container as the argument or am I missing something about
insert_iterator that makes this kind of usage possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

你曾走过我的故事 2025-01-09 17:39:34

该示例仅适用于在插入时不会使其迭代器失效的容器。

确切地。

我应该简单地摆脱迭代器并接受容器作为参数

这将是一种可能性。另一个原因是不使算法就地(即输出到不同的容器/输出迭代器)。

我是否遗漏了一些有关 insert_iterator 的信息,使得这种用法成为可能?

不。insert_iterator 用于重复插入到容器的单个位置,例如。通过变换算法。

The example works only for containers that do not invalidate their iterators on insertion.

Exactly.

Should I simply get rid of the iterators and accept a container as the argument

That would be one possibility. Another would be not making the algorithm in-place (ie. output to a different container/output-iterator).

am I missing something about insert_iterator that makes this kind of usage possible?

No. insert_iterator is meant for repeated inserts to a single place of a container eg. by a transform algorithm.

羁绊已千年 2025-01-09 17:39:34

您的实现问题与 insert_iterator 的属性完全无关。 C++ 标准库中的所有类型的插入迭代器都保证保持有效,即使您执行插入到容器中的操作可能会导致插入时的迭代器无效。当然,只有当所有插入仅通过插入迭代器执行时,这才是正确的。

换句话说,插入迭代器的实现保证迭代器将自动“修复”自身,即使插入导致容器中潜在的迭代器无效事件也是如此。

您的代码的问题是 beginend 迭代器可能会因插入某些容器类型而失效。您需要在代码中担心的是 beginend,而不是插入迭代器。

与此同时,由于某种原因,你完全倒退了。您似乎关心刷新插入迭代器(这是完全没有必要的),而完全忽略 beginend

The problems with your implementation have absolutely nothing to do with the properties of insert_iterator. All kinds of insert iterators in C++ standard library are guaranteed to remain valid, even if you perform insertion into a container that potentially invalidates iterators on insert. This is, of course, true only if all insertions are performed through only through the insert iterator.

In other words, the implementation of insert iterators guarantees that the iterator will automatically "heal" itself, even if the insertion lead to a potentially iterator-invalidating event in the container.

The problem with your code is that begin and end iterators can potentially get invalidated by insertion into certain container types. It is begin and end that you need to worry about in your code, not the insert iterator.

Meanwhile, you do it completely backwards for some reason. You seem to care about refreshing the insert iterator (which is completely unnecessary), while completely ignoring begin and end.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文