我有一个按需生成值的迭代器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的数据对象。当我在断言中插入一个断点时,我看到了我永远都不会想到的怪异值,例如0xCCCC-可能是未初始化的内存。发生的情况是reverse_iterator的解除引用运算符看起来像这样(来自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中的谓词更改为(Data候选)而不是(const Data&候选),则该谓词可以工作-但我很确定自己在那里的未定义行为很幸运。该引用无效,但是在内存被破坏之前,我正在复制数据。

我该怎么办?
  • 修复我的DataIterator,以便运算符*返回Data&而不是Data?我真的不知道这怎么可能。我的DataIterator返回数据而不是Data&的重点是因为我没有空间将所有未压缩的数据集保存在内存中,所以我创建了要按需查看的项目。也许我可以保留“当前”数据值-但是当您增加或减少DataIterator时,该引用将变得无效。 编辑 one of the answers suggests a shared_ptr
  • 写一个reverse_iterator的特殊化,并使它的取消引用运算符返回一个值而不是引用?这似乎是一件令人沮丧的工作,但可以理解,因为它是我的DataIterator在这里不能很好地发挥作用-而不是STL的其余部分。
  • 同样,也许做一个find_if逆向操作-可能比专门化reverse_iterator少。
  • 我还没想到的

  • 我可以对DataIterator做些什么,以防止别人花半天的时间弄清楚当他们从现在开始6个月后尝试相同的事情时出了什么问题吗?

    最佳答案

    并不是说我是这个想法的忠实拥护者,但是如果您在堆中分配了一个Data对象,然后向该对象返回了对shared_ptr的引用,那么,如果需要,外部世界可以将其保留更长的时间,并且对于您来说,“当您前进时,请忘记”。

    另一方面,实现自己的本地reverse_iterator可能会更大。这就是我对自己的链表所做的事情,因为我没有像gcc那样使用哨兵对象,也无法使用std::reverse_iterator。确实没有那么困难。

    关于c++ - 逆转按需迭代器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21103664/

    10-12 15:59