std :: insert_iterator和迭代器失效

时间:2012-02-06 00:29:27

标签: c++ std generic-programming

我尝试编写一个通用的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使这种用法成为可能吗?

2 个答案:

答案 0 :(得分:2)

  

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

完全。

  

我应该简单地删除迭代器并接受一个容器作为参数

那将是一种可能性。另一种方法是不在适当的位置制作算法(即输出到不同的容器/输出迭代器)。

  

我是否遗漏了有关insert_iterator的内容,使这种用法成为可能?

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

答案 1 :(得分:0)

您的实施问题与insert_iterator的属性完全无关。 C ++标准库中的所有类型的插入迭代器都保证保持有效,即使您执行插入到可能使插入上的迭代器无效的容器中也是如此。当然,只有通过插入迭代器执行所有插入时,这才是真的。

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

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

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