71

イテレータ (ベクトル、リスト、deque からのものかどうか...) が (まだ) 逆参照可能かどうか、つまり無効化されていないかどうかを確認する方法はありますか?

try-を使用していますcatchが、これを行うより直接的な方法はありますか?

例:(これは機能しません)

list<int> l;
for (i = 1; i<10; i++) {
    l.push_back(i * 10);
}

itd = l.begin();
itd++;
if (something) {
    l.erase(itd);
}

/* now, in other place.. check if it points to somewhere meaningful */
if (itd != l.end())
{
    //  blablabla
}
4

12 に答える 12

65

「イテレータは有効か」というのは、コンテナの変更 (ベクトルへの挿入/ベクトルからの削除など) によって無効化されていないことを意味していると思います。その場合、いいえ、イテレータが (安全に) 参照解除可能かどうかを判断できません。

于 2010-01-14T08:37:10.970 に答える
26

jdehaan が言ったように、イテレータが無効化されておらず、コンテナを指している場合は、それを と比較して確認できますcontainer.end()

ただし、イテレータが特異である場合 (イテレータが初期化されていないか、コンテナでの変更操作の後に無効になったため (たとえば、ベクトルの容量を増やすと、ベクトルのイテレータが無効になります))、唯一の操作であることに注意してください。あなたはそれを実行することが許可されています。つまり、イテレータが特異かどうかをチェックすることはできません。

std::vector<int>::iterator iter = vec.begin();
vec.resize(vec.capacity() + 1);
// iter is now singular, you may only perform assignment on it,
// there is no way in general to determine whether it is singular or not
于 2010-01-14T08:37:44.190 に答える
13

移植不可能な回答: はい - Visual Studio で

Visual Studio の STL イテレータには、まさにこれを行う「デバッグ」モードがあります。出荷ビルドではこれを有効にしたくないでしょう (オーバーヘッドがあります) が、チェック ビルドでは便利です。

ここで VC10 について読んでください(このシステムはリリースごとに変更される可能性があり、実際には変更されるため、バージョンに固有のドキュメントを見つけてください)。

編集また、追加する必要があります。Visual Studio のデバッグ イテレータは、使用するとすぐに爆発するように設計されています (代わりに、未定義の動作)。それらの状態の「クエリ」を許可しないでください。

于 2010-01-14T16:49:55.007 に答える
10

通常、次のように end() と異なるかどうかを確認してテストします。

if (it != container.end())
{
   // then dereference
}

また、ロジックを置き換えるために例外処理を使用することは、設計とパフォーマンスの点で良くありません。あなたの質問は非常に優れており、コードを置き換える価値があります。名前が示すような例外処理は、まれな予期しない問題にのみ使用されます。

于 2010-01-14T08:33:17.747 に答える
7

イテレータ (ベクトル、リスト、deque からのものかどうか...) が (まだ) 参照解除可能かどうか、つまり無効化されていないかどうかを確認する方法はありますか?

いいえ、ありません。代わりに、イテレータが存在する間はコンテナへのアクセスを制御する必要があります。次に例を示します。

  • コンテナーのインスタンス化されたイテレーターをまだ使用している間は、スレッドはコンテナーを変更 (イテレーターを無効化) しないでください。

  • スレッドの反復中に他のスレッドがコンテナーを変更する可能性がある場合、このシナリオをスレッド セーフにするために、スレッドがコンテナーに対して何らかのロックを取得する必要があります (これにより、他のスレッドがコンテナーを変更するのを防ぐことができます)。イテレータを使用しています)

例外をキャッチするなどの回避策は機能しません。

これは、「ポインターが有効かどうかをテスト/検出できますか?」というより一般的な問題の特定の例であり、その答えは通常、「いいえ、テストできません。代わりに、すべてのメモリ割り当てを管理する必要があります。特定のポインターがまだ有効かどうかを知るための削除」。

于 2010-01-14T08:54:09.443 に答える
3

イテレータが「範囲外」の場合、試行してキャッチすることは安全ではありません。そうしないか、少なくともめったにスローしません。

alemjerus が言うには、イテレータはいつでも逆参照できます。どんな醜さが下にあっても。メモリの他の領域を繰り返し処理し、他のオブジェクトを保持する可能性のある他の領域に書き込むことは十分に可能です。私はコードを見ていて、特別な理由もなく変数が変化するのを見てきました。これは、検出するのが非常に難しいバグです。

また、要素を挿入および削除すると、すべての参照、ポインター、および反復子が無効になる可能性があることを覚えておくのが賢明です。

私の最善のアドバイスは、イテレータを管理下に置き、いわば「行末」にいるかどうかをテストできるように、常に「終了」イテレータを手元に置いておくことです。

于 2010-01-14T08:36:39.297 に答える
2

一部の STL コンテナーでは、イテレーターの現在の値を消去すると、現在のイテレーターが無効になります。これは、消去操作によってコンテナの内部メモリ構造が変更され、既存のイテレータのインクリメント オペレータが未定義の場所を指しているために発生します。

以下を実行すると、消去関数に渡される前に反復子が増分されます。

if (something) l.erase(itd++);

于 2010-03-07T06:02:26.570 に答える
0

std コンテナーの消去関数のパラメーターの型 (質問に記載されているように、つまり、ベクター、リスト、deque からのものかどうかなど) は常に、このコンテナーの iterator onlyです。

この関数は、最初に指定された反復子を使用して、この反復子が指す要素とそれに続く要素をコンテナーから除外します。1 つの反復子に対して 1 つの要素のみを消去するコンテナーもあれば、1 つの反復子 (この反復子が指す要素を含む) に続くすべての要素をコンテナーの末尾まで消去するコンテナーもあります。消去関数が 2 つの反復子を受け取った場合、各反復子が指す 2 つの要素がコンテナーから消去され、それらの間の残りの要素もすべてコンテナーから消去されます。 std コンテナの関数は無効になります! また

コンテナーから消去された要素を指していた各イテレーターは無効になりますが、コンテナーの末尾を通過しません!

つまり、コンテナーから消去された要素を指していたイテレーターは、container.end() と比較できません。このイテレータは無効なので、逆参照できません。つまり、* 演算子も -> 演算子も使用できません。インクリメントもできません。つまり、++ 演算子も使用できません。デクリメントもできません。つまり、オペレーター。

それも比較にならない!!! IE では、== 演算子も != 演算子も使用できません。

実際には、標準反復子で宣言および定義されている演算子は使用できません。null ポインターなど、この反復子では何もできません。

無効な反復子で何かを行うと、プログラムがすぐに停止し、プログラムがクラッシュしてアサーション ダイアログ ウィンドウが表示されることさえあります。どのオプションを選択しても、どのボタンをクリックしても、プログラムを続行する方法はありません。[中止] ボタンをクリックするだけで、プログラムとプロセスを終了できます。

コンテナの先頭に設定するか、単に無視しない限り、無効なイテレータに対して他に何もする必要はありません。

しかし、イテレータをどうするかを決める前に、使用しているコンテナの消去関数を呼び出す場合、まずこのイテレータが無効かどうかを知る必要があります。

与えられた反復子が無効かどうかをチェックし、テストし、認識し、true を返す関数を自分で作成しました。memcpy 関数を使用して、任意のオブジェクト、アイテム、構造、クラスなどの状態を取得できます。もちろん、最初は常に memset 関数を使用して、新しいバッファー、構造、クラス、または任意のオブジェクトまたはアイテムをクリアまたは空にします。 :

bool IsNull(list<int>::iterator& i) //In your example, you have used list<int>, but if your container is not list, then you have to change this parameter to the type of the container you are using, if it is either a vector or deque, and also the type of the element inside the container if necessary.
{
    byte buffer[sizeof(i)];
    memset(buffer, 0, sizeof(i));
    memcpy(buffer, &i, sizeof(i));
    return *buffer == 0; //I found that the size of any iterator is 12 bytes long. I also found that if the first byte of the iterator that I copy to the buffer is zero, then the iterator is invalid. Otherwise it is valid. I like to call invalid iterators also as "null iterators".
}

そこに投稿する前にこの機能をテストしたところ、この機能が機能していることがわかりました。

私はあなたの質問に完全に答え、またあなたを大いに助けたことを願っています!

于 2015-01-14T17:23:00.807 に答える
-1

インクリメントで消去を使用:

   if (何か) l.erase(itd++);

イテレータの有効性をテストできます。

于 2010-01-20T17:03:13.243 に答える
-3
if (iterator != container.end()) {
   iterator is dereferencable !
}

イテレータが と等しくcontainer.end()なく、参照解除できない場合は、何か問題があります。

于 2010-01-14T08:34:08.600 に答える