我有一个迭代器 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 candidate) 而不是 (const Data& candidate),则谓词有效 - 但我很确定我只是幸运地遇到了那里的未定义行为。引用无效,但我正在内存被破坏之前复制数据。
我能做什么?
- 修复我的 DataIterator 以便 operator* 返回 Data& 而不是 Data?我真的不明白这怎么可能。我的 DataIterator 返回 Data 而不是 Data& 的全部意义是因为我没有空间在内存中保存整个未压缩的数据集,所以我创建了您想要按需查看的项目。
也许我可以保留“当前”数据值 - 但当您递增或递减 DataIterator 时,该引用将变得无效。编辑 one of the answers suggests a shared_ptr - 编写一个 reverse_iterator 的特例并让它的取消引用运算符返回一个值而不是一个引用?这看起来是一个令人沮丧的工作量,但可以理解,因为它是我的 DataIterator 在这里表现不佳 - 而不是 STL 的其余部分。
- 按照同样的思路,也许做一个反向的 find_if - 可能比专门化 reverse_iterator 工作更少。
- 其他我没有想到的
我可以对 DataIterator 做些什么来防止其他人在 6 个月后尝试同样的事情时花半天时间弄清楚问题出在哪里?
最佳答案
并不是说我很喜欢这个想法,但是如果你堆分配了一个 Data
对象,然后返回一个 shared_ptr
的 ref 给它,那会如果需要,允许外界更长时间地捕获它,并让您在向前迈进时“忘记”它。
另一方面,实现您自己的原生 reverse_iterator
可能是一个更大的胜利。这就是我为自己的链表所做的,因为我没有像 gcc
那样使用标记对象,也不能使用 std::reverse_iterator
。这真的没有那么难。
关于c++ - 反转按需迭代器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21103664/