5

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

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 的取消引用运算符看起来像这样(来自 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 Candidate) 而不是 (const Data& Candidate) 则该谓词有效 - 但我很确定我只是对那里未定义的行为感到幸运。引用无效,但我在内存被破坏之前制作了数据的副本。

我能做些什么?

  1. 修复我的 DataIterator 以便 operator* 返回 Data& 而不是 Data?我真的不明白这怎么可能。我的 DataIterator 返回 Data 而不是 Data& 的全部意义在于我没有空间将整个未压缩数据集保存在内存中,因此我创建了您想要按需查看的项目。 也许我可以保留“当前”数据值 - 但是当您增加或减少 DataIterator 时,该引用将变得无效。 编辑 其中一个答案建议使用 shared_ptr
  2. 写一个 reverse_iterator 的特化,让它的解引用操作符返回一个值而不是一个引用?这似乎是一项令人沮丧的工作,但可以理解,因为我的 DataIterator 在这里表现不佳 - 而不是 STL 的其余部分。
  3. 沿着同样的思路,也许做一个反向的 find_if - 可能比专门化 reverse_iterator 的工作少。
  4. 其他我没有想到的东西

我可以对 DataIterator 做些什么来防止其他人在 6 个月后尝试同样的事情时花半天时间弄清楚出了什么问题?

4

3 回答 3

1

并不是说我是这个想法的忠实拥护者,但是如果您堆分配了一个Data对象,然后将引用返回shared_ptr给它,那将允许外部世界在需要时保留它更长的时间,并且让您“忘记”当你向前走的时候。

另一方面,实现你自己的原生reverse_iterator可能是一个更大的胜利。这就是我为我自己的链表所做的,因为我没有像 do 那样使用哨兵对象gcc,也不能使用std::reverse_iterator. 真的没那么难。

于 2014-01-14T00:53:17.847 回答
1

这是因为reverse_iterator界面是在decltype. 今天,这将被写成

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

在 C++14中,甚至不需要尾随返回类型,因为它可以被推断出来。

decltype(auto) operator*() const
{   // return designated value
    DataIterator _Tmp = current;
    return (*--_Tmp);
}
于 2014-01-14T01:00:07.787 回答
0

我最终在评论中接受了凯西的建议。他没有将其发布为我可以接受的答案,因此我将自己写出来。

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

reference operator*() const

value operator*() const
于 2014-01-16T22:12:35.737 回答