STLのerase()落とし穴-ディエゼルの故障問題についてのまとめ
次の資料はInternet&著作から整理します。
STLの容器は格納方式によって二種類に分けられ、一つは配列形式で格納された容器(例えば、vector、deque)である。別のクラスは、リスト、set、mapなどの不連続なノード形式で格納されるコンテナである。erase方法を使用して要素を削除する場合、いくつかの問題に注意する必要があります。
1.list、set、map容器
このように、リスト、set、またはmapを使用して要素を削除するときに使用できます。
1.1正しい書き方1
正しい使い方1:erase方法の戻り値で次の要素の位置を取得する
正しい使い方2:eraseメソッドを呼び出す前に「+」を使って次の要素の位置を取得します。
エラー使用方法1:eraseメソッドを呼び出した後、次の要素の位置を「+」で取得します。これは、eraseメソッドを呼び出した後、その要素の位置がすでに
削除され、この古い位置から次の位置を取得すると異常が発生します。
エラー使用方法2:同上。
2.vector、deque容器
vector、dequeを使用して要素を削除した場合、eraseの戻り値によって次の要素の位置を取得することもできます。
2.1正しい書き方
注意:vector、dequeは上のように「正しい使い方2」の方法でくまなく削除することができません。理由はEffective STLアイテム9を参照してください。以下に抜粋する:
1) 関連する容器(map、set、multimap、multistet)については、現在のiteratorを削除し、現在のiteratorを無効にするだけで、eraseの時に、現在のiteratorをインクリメントすればいいです。これは、mapなどの容器は、赤と黒の木を使って実現されており、一つの結点を挿入、削除することは他の結点に影響を与えないからです。
2)シーケンス型容器(vector、dequeなど)に対して、現在のiteratorを削除すると、後のすべての要素のiteratorが無効になります。これは、vetor、dequeが連続的に割り当てられたメモリを使用しているためで、一つの要素を削除すると、後ろのすべての要素が前の位置に移動します。幸いなことに、erase方法は次の効果的なiteratorに戻ります。
3.シーケンサが失効した場合
3.1 vector
内部データ構造:行列。
各要素にランダムにアクセスします。必要な時間は定数です。
最後に要素を追加または削除するために必要な時間は要素の数に関係なく、中間または最初に要素を追加または削除するために必要な時間は要素の数に応じて直線的に変化します。
動的に要素を増加または減少させ、メモリ管理は自動的に完了するが、プログラマは、reerve()メンバー関数を使用してメモリを管理することができる。
vectorのディケンサはメモリ再割り当て時に無効になります。capacity()-size()を超える要素をvectorに挿入するとメモリが再割り当てされ、すべてのサブジェネレータが無効になります。そうでなければ、現在の要素を指した後の任意の要素のディケンサは無効になります。要素を削除すると、削除された要素の次の要素を指しているすべてのリズミカルが無効になります。
3.2 deque
内部データ構造:行列。
各要素にランダムにアクセスします。必要な時間は定数です。
最初と最後に要素を追加するために必要な時間は要素の数に関係なく、中間に要素を追加または削除するために必要な時間は要素の数に応じて直線的に変化します。
メモリ管理が自動的に完了し、メモリ管理のためのメンバー関数が提供されません。
任意の要素を追加すると、dequeのローズマリーが無効になります。dequeの中間で要素を削除すると、ディエゼルが無効になります。dequeのヘッダまたは最後に要素を削除すると、その要素を指すローズマリーだけが無効になります。
3.3リスト
内部データ構造:双方向リングチェーン表。
ランダムに要素にアクセスできませんでした。
双方向アクセス可能です。
最初、最後、中間のどこでも要素を追加または削除するために必要な時間は定数です。
要素を動的に増加または減少させ、メモリ管理が自動的に完了します。
任意の要素を追加しても、シーケンサは無効になりません。要素を削除するときは、現在削除されている要素を指すローズマリーを除いて、他のローズマリーは無効になりません。
3.4 slist
内部データ構造:一方向チェーン表。
両方を遍歴してはいけません。前から後まで歩くしかないです。
他の特性はリストと似ています。
3.5ショック
アダプターは、任意のタイプのシーケンスコンテナをスタックに変換することができ、一般にDequeをサポートするシーケンスコンテナとして使用する。
元素は後進先のみ出すことができます。
ステージ全体を巡回してはいけません。
3.6 queue
アダプターは、任意のタイプのシーケンスコンテナを行列に変換してもよく、一般的にはDequeをサポートするシーケンスコンテナとして使用しています。
元素は先入れ先出しのみ可能です。
全体のqueueを遍歴することはできません。
3.7 pristy_queue
アダプターは、任意のタイプのシーケンスコンテナを優先列に変換してもよく、一般的にはvectorを底層記憶方式として使用する。
最初の元素にしかアクセスできません。全体のprorityを遍歴することはできません。queue
最初の要素は常に優先度が一番高い要素です。
3.8セット
キーと値が等しいです。
キーが一意です。
要素はデフォルトで昇順に並べられます。
ローズマリーが指している要素が削除された場合、そのローズマリーは無効になります。その他の任意の要素の追加、削除の操作は、サブコマンダーを無効にしません。
3.9 multiset
キーは一意ではないことができます。
他の特徴はセットと同じです。
3.10 hash_セット
setと比較して、その中の要素は必ずしも順序付けされているのではなく、使用されているhash関数によって割り当てられています。より速い検索速度を提供できます。
他の特徴はセットと同じです。
3.11 hash_multiset
キーは一意ではないことができます。
その他の特徴とhash_セットは同じです。
3.12 map
キーが一意です。
要素の標準ボタンの昇順の配置。
ローズマリーが指している要素が削除された場合、そのローズマリーは無効になります。その他の任意の要素の追加、削除の操作は、サブコマンダーを無効にしません。
3.13 multimap
キーは一意ではないことができます。
他の特徴はmapと同じです。
3.14 hash_map
mapと比較して、その中の要素は必ずしもボタンの値を並べ替えるのではなく、使っているhash関数によって割り当てられたので、より速い検索速度を提供することができます(もちろんhash関数にも関係があります)。
他の特徴はmapと同じです。
3.15 hash_multimap
キーは一意ではないことができます。
その他の特徴とhash_mapは同じです。
以上、STLのerase()落とし穴-ディエゼルの故障問題についてまとめました。どうぞよろしくお願いします。
STLの容器は格納方式によって二種類に分けられ、一つは配列形式で格納された容器(例えば、vector、deque)である。別のクラスは、リスト、set、mapなどの不連続なノード形式で格納されるコンテナである。erase方法を使用して要素を削除する場合、いくつかの問題に注意する必要があります。
1.list、set、map容器
このように、リスト、set、またはmapを使用して要素を削除するときに使用できます。
1.1正しい書き方1
std::list< int> List;
std::list< int>::iterator itList;
for( itList = List.begin(); itList != List.end(); )
{
if( WillDelete( *itList) )
{
itList = List.erase( itList);
}
else
itList++;
}
1.2正しい書き方2
std::list< int> List;
std::list< int>::iterator itList;
for( itList = List.begin(); itList != List.end(); )
{
if( WillDelete( *itList) )
{
List.erase( itList++);
}
else
itList++;
}
1.3間違った書き方1
std::list< int> List;
std::list< int>::iterator itList;
for( itList = List.begin(); itList != List.end(); itList++)
{
if( WillDelete( *itList) )
{
List.erase( itList);
}
}
1.4間違った書き方2
std::list< int> List;
std::list< int>::iterator itList;
for( itList = List.begin(); itList != List.end(); )
{
if( WillDelete( *itList) )
{
itList = List.erase( ++itList);
}
else
itList++;
}
1.5分析正しい使い方1:erase方法の戻り値で次の要素の位置を取得する
正しい使い方2:eraseメソッドを呼び出す前に「+」を使って次の要素の位置を取得します。
エラー使用方法1:eraseメソッドを呼び出した後、次の要素の位置を「+」で取得します。これは、eraseメソッドを呼び出した後、その要素の位置がすでに
削除され、この古い位置から次の位置を取得すると異常が発生します。
エラー使用方法2:同上。
2.vector、deque容器
vector、dequeを使用して要素を削除した場合、eraseの戻り値によって次の要素の位置を取得することもできます。
2.1正しい書き方
std::vector< int> Vec;
std::vector< int>::iterator itVec;
for( itVec = Vec.begin(); itVec != Vec.end(); )
{
if( WillDelete( *itVec) )
{
itVec = Vec.erase( itVec);
}
else
itList++;
}
2.2注意注意:vector、dequeは上のように「正しい使い方2」の方法でくまなく削除することができません。理由はEffective STLアイテム9を参照してください。以下に抜粋する:
1) 関連する容器(map、set、multimap、multistet)については、現在のiteratorを削除し、現在のiteratorを無効にするだけで、eraseの時に、現在のiteratorをインクリメントすればいいです。これは、mapなどの容器は、赤と黒の木を使って実現されており、一つの結点を挿入、削除することは他の結点に影響を与えないからです。
for (iter = cont.begin(); it != cont.end();)
{
(*iter)->doSomething();
if (shouldDelete(*iter))
cont.erase(iter++);
else
++iter;
}
iterからeraseに送る方法はコピーですので、iter++は次の要素を指します。2)シーケンス型容器(vector、dequeなど)に対して、現在のiteratorを削除すると、後のすべての要素のiteratorが無効になります。これは、vetor、dequeが連続的に割り当てられたメモリを使用しているためで、一つの要素を削除すると、後ろのすべての要素が前の位置に移動します。幸いなことに、erase方法は次の効果的なiteratorに戻ります。
for (iter = cont.begin(); iter != cont.end();)
{
(*it)->doSomething();
if (shouldDelete(*iter))
iter = cont.erase(iter);
else
++iter;
}
3)listにとって、不連続的に割り当てられたメモリを使用しており、そのerase方法は次の効果的なiteratorに戻るので、上記の2つの方法が使用できます。3.シーケンサが失効した場合
3.1 vector
内部データ構造:行列。
各要素にランダムにアクセスします。必要な時間は定数です。
最後に要素を追加または削除するために必要な時間は要素の数に関係なく、中間または最初に要素を追加または削除するために必要な時間は要素の数に応じて直線的に変化します。
動的に要素を増加または減少させ、メモリ管理は自動的に完了するが、プログラマは、reerve()メンバー関数を使用してメモリを管理することができる。
vectorのディケンサはメモリ再割り当て時に無効になります。capacity()-size()を超える要素をvectorに挿入するとメモリが再割り当てされ、すべてのサブジェネレータが無効になります。そうでなければ、現在の要素を指した後の任意の要素のディケンサは無効になります。要素を削除すると、削除された要素の次の要素を指しているすべてのリズミカルが無効になります。
3.2 deque
内部データ構造:行列。
各要素にランダムにアクセスします。必要な時間は定数です。
最初と最後に要素を追加するために必要な時間は要素の数に関係なく、中間に要素を追加または削除するために必要な時間は要素の数に応じて直線的に変化します。
メモリ管理が自動的に完了し、メモリ管理のためのメンバー関数が提供されません。
任意の要素を追加すると、dequeのローズマリーが無効になります。dequeの中間で要素を削除すると、ディエゼルが無効になります。dequeのヘッダまたは最後に要素を削除すると、その要素を指すローズマリーだけが無効になります。
3.3リスト
内部データ構造:双方向リングチェーン表。
ランダムに要素にアクセスできませんでした。
双方向アクセス可能です。
最初、最後、中間のどこでも要素を追加または削除するために必要な時間は定数です。
要素を動的に増加または減少させ、メモリ管理が自動的に完了します。
任意の要素を追加しても、シーケンサは無効になりません。要素を削除するときは、現在削除されている要素を指すローズマリーを除いて、他のローズマリーは無効になりません。
3.4 slist
内部データ構造:一方向チェーン表。
両方を遍歴してはいけません。前から後まで歩くしかないです。
他の特性はリストと似ています。
3.5ショック
アダプターは、任意のタイプのシーケンスコンテナをスタックに変換することができ、一般にDequeをサポートするシーケンスコンテナとして使用する。
元素は後進先のみ出すことができます。
ステージ全体を巡回してはいけません。
3.6 queue
アダプターは、任意のタイプのシーケンスコンテナを行列に変換してもよく、一般的にはDequeをサポートするシーケンスコンテナとして使用しています。
元素は先入れ先出しのみ可能です。
全体のqueueを遍歴することはできません。
3.7 pristy_queue
アダプターは、任意のタイプのシーケンスコンテナを優先列に変換してもよく、一般的にはvectorを底層記憶方式として使用する。
最初の元素にしかアクセスできません。全体のprorityを遍歴することはできません。queue
最初の要素は常に優先度が一番高い要素です。
3.8セット
キーと値が等しいです。
キーが一意です。
要素はデフォルトで昇順に並べられます。
ローズマリーが指している要素が削除された場合、そのローズマリーは無効になります。その他の任意の要素の追加、削除の操作は、サブコマンダーを無効にしません。
3.9 multiset
キーは一意ではないことができます。
他の特徴はセットと同じです。
3.10 hash_セット
setと比較して、その中の要素は必ずしも順序付けされているのではなく、使用されているhash関数によって割り当てられています。より速い検索速度を提供できます。
他の特徴はセットと同じです。
3.11 hash_multiset
キーは一意ではないことができます。
その他の特徴とhash_セットは同じです。
3.12 map
キーが一意です。
要素の標準ボタンの昇順の配置。
ローズマリーが指している要素が削除された場合、そのローズマリーは無効になります。その他の任意の要素の追加、削除の操作は、サブコマンダーを無効にしません。
3.13 multimap
キーは一意ではないことができます。
他の特徴はmapと同じです。
3.14 hash_map
mapと比較して、その中の要素は必ずしもボタンの値を並べ替えるのではなく、使っているhash関数によって割り当てられたので、より速い検索速度を提供することができます(もちろんhash関数にも関係があります)。
他の特徴はmapと同じです。
3.15 hash_multimap
キーは一意ではないことができます。
その他の特徴とhash_mapは同じです。
以上、STLのerase()落とし穴-ディエゼルの故障問題についてまとめました。どうぞよろしくお願いします。