2014-01-13 24 views
5

私は値をオンデマンドで生成するイテレータDataIteratorを持っているので、参照解除演算子はデータ&ではなく、データを返します。 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 
} 

問題がどこにある最後の行がある - 一時的なデータが作成されますし、そのデータへの参照が返されます。参照はすぐに無効です。

(constデータ&候補)の代わりに(データ候補)std :: find_ifで述語を変更すると、述語が機能しますが、私はそこで未定義の動作をしているだけです。参照は無効ですが、メモリが壊れる前にデータのコピーを作成しています。

どうすればよいですか?そのオペレータは*ではなくデータのデータ&を返すよう

  1. は私DataIteratorを修正しますか?私はこれがどのように可能であるか実際見ていない。データ&の代わりにデータを返すDataIterator全体のポイントは、非圧縮データセット全体をメモリに保持する余地がないためです。必要に応じて表示するアイテムを作成します。 たぶん、私は '現在の'データ値を保持することができますが、その参照はDataIteratorをインクリメントまたはデクリメントすると無効になります。編集one of the answers suggests a shared_ptr
  2. reverse_iteratorの特殊化を作成し、その参照解除演算子を参照ではなく値を返すようにしますか?これは不便な作業のようですが、STLの残りの部分ではなく、ここでうまく動作しないDataIteratorなので分かります。
  3. 同じ行に沿って、reverse_iteratorに特化したfind_ifを作成するよりも、逆になるfind_ifを作成するほうが簡単かもしれません。
  4. 私は

と考えていない何か他のものは、彼らが今から6ヶ月同じことをしようとすると、何が間違って考え出す半日を吹いてから、他の誰かを防ぐことができます私はDataIteratorに行うことができます何かありますか?

+0

reference operator*() const 

を変更すると、なぜあなたは、このタスクのためのイテレータを選んだのですか? –

+0

データを 'ベクトル'にコピーし、そのベクトルに 'reverse_iterator'を使用します –

+0

基礎となるデータが非常に大きいが圧縮されているため、イテレータが選択されました。イテレータは、反復処理を行う際に、一度に1つずつデータを解凍します。これにより、データセットを見ることができ、複数の非常に大きなデータセットをメモリに保持しなくても、派生したデータセットを遅延生成することができます。 –

答えて

0

私は、コメントにCaseyの提案を出しました。彼はそれを私が受け入れる答えとして掲示しなかったので、私はそれを自分自身で書く。

参照の代わりに値を返すDataIteratorのreverse_iteratorを特殊化しました。これ関与コピーは/ DataIteratorするテンプレート引数のいずれかを指定し、xutilityから実装を貼り付け、および

value operator*() const 
1

私はこのアイデアを大好きに思っていませんが、Dataオブジェクトを割り振ってからshared_ptrに参照を返した場合、必要に応じて外界がそれを長く保持できるようになります。あなたが前進するときにあなたがそれを "忘れる"ことができます。

一方、独自のネイティブreverse_iteratorを実装すると、より大きな成果を上げる可能性があります。それはgccのようなセンチネルオブジェクトを使わなかったので私自身のリンクされたリストのためにしたもので、std::reverse_iteratorを使うことができませんでした。それは本当に難しいことではありませんでした。

+0

shared_ptrへの参照は生き続けるのですか?それにもかかわらず - もし私が再び始まったら、参照カウントのいくつかのタイプがおそらく行く方法でしょう。残念ながら、現時点でのコードベースの変更は大きすぎると思います。 –

+0

'shared_ptr'への参照はそれ自体を生かし続けることはできませんが、もし誰かがそれを使いたいのであれば、それを別の' shared_ptr'にコピーするでしょう。それは生き続けるでしょう。 – woolstar

+0

私は自分の頭に欠けていたステップは、反復子のプライベートフィールドにshared_ptrをキャッシュしていた。イテレータを移動するとプライベートフィールドがクリアされ、その間に他の人がコピーを取得した場合、基礎となるデータはそのまま残ります –

1

が存在する前にreverse_iteratorインターフェイスが設計されているからです。今日、それは

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

in C++14のように書かれることになることが推測できるため、でも末尾の戻り値の型は、必要とされることはありません。

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

私の良さ..そのC++ 14コードはきれいに見えます。しかし、私はそれに慣れているかどうかは分かりません。私は、それはC#とjavascriptではあまりにもvarと似ていると思います。私が好きなタイプを見ているだけのことがあります。私はこれを初めて見ていると便利です。私の+1。 – Brandon