オンデマンドで値を生成する反復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 の述語を (const Data& 候補) の代わりに (データ候補) を取るように変更すると、述語は機能しますが、未定義の動作で幸運になっていると確信しています。参照は無効ですが、メモリが破壊される前にデータのコピーを作成しています。
私に何ができる?
- operator* が Data ではなく Data& を返すように DataIterator を修正しますか? これがどのように可能かはよくわかりません。Data& の代わりに Data を返す DataIterator の全体的なポイントは、非圧縮データ セット全体をメモリに保持する余地がないため、必要に応じて表示する項目を作成することです。
「現在の」データ値を保持することもできますが、DataIterator をインクリメントまたはデクリメントすると、その参照は無効になります。回答の 1 つを編集 すると、shared_ptr が提案されます - reverse_iterator の特殊化を作成し、その逆参照演算子が参照ではなく値を返すようにしますか? これは苛立たしい量の作業のように思えますが、ここでうまく機能していないのは私の DataIterator であり、STL の残りの部分ではないため、理解できます。
- 同様に、おそらく逆方向の find_if を作成します。おそらく、reverse_iterator を特殊化するよりも作業が少なくなります。
- 私が考えていなかった他の何か
他の誰かが今から 6 か月後に同じことをしようとしたときに何が問題なのかを理解するために半日吹き飛ばされるのを防ぐために、DataIterator に対してできることはありますか?