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 の述語を (const Data& 候補) の代わりに (データ候補) を取るように変更すると、述語は機能しますが、未定義の動作で幸運になっていると確信しています。参照は無効ですが、メモリが破壊される前にデータのコピーを作成しています。

私に何ができる?

  1. operator* が Data ではなく Data& を返すように DataIterator を修正しますか? これがどのように可能かはよくわかりません。Data& の代わりに Data を返す DataIterator の全体的なポイントは、非圧縮データ セット全体をメモリに保持する余地がないため、必要に応じて表示する項目を作成することです。 「現在の」データ値を保持することもできますが、DataIterator をインクリメントまたはデクリメントすると、その参照は無効になります。 回答の 1 つを編集 すると、shared_ptr が提案されます
  2. reverse_iterator の特殊化を作成し、その逆参照演算子が参照ではなく値を返すようにしますか? これは苛立たしい量の作業のように思えますが、ここでうまく機能していないのは私の DataIterator であり、STL の残りの部分ではないため、理解できます。
  3. 同様に、おそらく逆方向の find_if を作成します。おそらく、reverse_iterator を特殊化するよりも作業が少なくなります。
  4. 私が考えていなかった他の何か

他の誰かが今から 6 か月後に同じことをしようとしたときに何が問題なのかを理解するために半日吹き飛ばされるのを防ぐために、DataIterator に対してできることはありますか?

4

3 に答える 3

1

私はこのアイデアの大ファンというわけではありませんが、Dataオブジェクトをヒープに割り当ててから参照を返すと、shared_ptr必要に応じて外の世界がそれをより長く保持し、「忘れる」ことができます。あなたが一歩前に出るとき、それについて。

一方、独自のネイティブを実装するreverse_iteratorと、より大きなメリットが得られる可能性があります。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

コメントでCaseyの提案に行きました。彼は私が受け入れることができる答えとしてそれを投稿しなかったので、私はそれを自分で書きます.

参照の代わりに値を返す DataIterator の reverse_iterator を特殊化しました。これには、xutility から実装をコピーして貼り付け、テンプレート引数の 1 つを DataIterator に指定し、変更する必要がありました。

reference operator*() const

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