反转按需迭代器

时间:2014-01-13 23:50:39

标签: c++ stl iterator reverse-iterator

我有一个按需生成值的迭代器DataIterator,因此取消引用运算符返回一个Data,而不是Data&。我认为这是一件好事,直到我试图通过将数据包装在reverse_iterator中来反转数据DataIterator。

DataCollection collection

std::reverse_iterator<DataIterator> rBegin(iter) //iter is a DataIterator that's part-way through the collection
std::reverse_iterator<DataIterator> rEnd(collection.cbegin());

auto Found = std::find_if(
    rBegin, 
    rEnd,
    [](const Data& candidate){
        return candidate.Value() == 0x00;
});

当我运行上面的代码时,它永远不会找到一个值等于0的Data对象,即使我知道一个存在。当我在谓词中插入一个断点时,我会看到奇怪的值,我永远不会期望看到像0xCCCC - 可能是未初始化的内存。会发生什么是reverse_iterator的dereference运算符看起来像这样(来自xutility - Visual Studio 2010)

Data& operator*() const
{   // return designated value
    DataIterator _Tmp = current;
    return (*--_Tmp); //Here's the problem - the * operator on DataIterator returns a value instead of a reference
}

最后一行是问题所在 - 创建临时数据并返回对该数据的引用。该引用立即无效。

如果我将std :: find_if中的谓词更改为(数据候选者)而不是(const Data&amp; candidate),那么谓词就可以了 - 但我很确定我只是幸运地遇到了未定义的行为。该引用无效,但我在内存遭到破坏之前正在复制数据。

我该怎么办?

  1. 修复我的DataIterator,以便操作员*返回数据&amp;而不是数据?我真的不明白这是怎么回事。我的DataIterator返回Data而不是Data&amp;的整点。是因为我没有空间将整个未压缩的数据集保存在内存中,所以我创建了你想要按需查看的项目。 也许我可以保留'当前'数据值 - 但是当你递增或递减DataIterator时,该引用将变为无效。 编辑 one of the answers suggests a shared_ptr
  2. 编写reverse_iterator的特化并使其解引用运算符返回值而不是引用?这似乎是令人沮丧的工作量,但可以理解,因为这是我的DataIterator在这里不好玩 - 而不是STL的其余部分。
  3. 沿着同样的路线,也许让一个反向的find_if - 可能比专门化reverse_iterator要少。
  4. 我没有想到的其他东西
  5. 我可以对DataIterator做些什么,以防止其他人在6个月后尝试同样的事情时,用半天时间弄清楚出了什么问题?

3 个答案:

答案 0 :(得分:1)

并不是说我非常喜欢这个主意,但是如果你分配了一个Data对象,然后将一个引用返回到shared_ptr,这将允许外部世界保持如果需要,可以更长时间地使用它,当你向前迈进时,你就会“忘记”它。

另一方面,实施自己的原生reverse_iterator可能是一个更大的胜利。这就是我为自己的链表做的事情,因为我没有使用像gcc那样的标记对象而且不能使用std::reverse_iterator。这真的不是那么难。

答案 1 :(得分:1)

这是因为reverse_iterator接口是在decltype存在之前设计的。今天,那将写成

auto operator*() const -> decltype(*current)
{   // return designated value
    DataIterator _Tmp = current;
    return (*--_Tmp);
}

in C++14,甚至不需要尾随返回类型,因为可以推断它。

decltype(auto) operator*() const
{   // return designated value
    DataIterator _Tmp = current;
    return (*--_Tmp);
}

答案 2 :(得分:0)

我最后在评论中提到了凯西的建议。他没有把它作为我能接受的答案发布,所以我会自己写出来。

我对DataIterator的reverse_iterator进行了专门化,返回值而不是引用。这涉及从xutility复制/粘贴实现,指定一个模板参数作为DataIterator,并更改

reference operator*() const

value operator*() const