我有一个按需生成值的迭代器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做些什么,以防止别人花半天的时间弄清楚当他们从现在开始6个月后尝试相同的事情时出了什么问题吗?
最佳答案
并不是说我是这个想法的忠实拥护者,但是如果您在堆中分配了一个Data
对象,然后向该对象返回了对shared_ptr
的引用,那么,如果需要,外部世界可以将其保留更长的时间,并且对于您来说,“当您前进时,请忘记”。
另一方面,实现自己的本地reverse_iterator
可能会更大。这就是我对自己的链表所做的事情,因为我没有像gcc
那样使用哨兵对象,也无法使用std::reverse_iterator
。确实没有那么困难。
关于c++ - 逆转按需迭代器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21103664/