2016-07-15 4 views
0

std::vectorからオブジェクトを消去しようとするとアクセス違反が発生するラムダがあります。イテレータは正しいオブジェクトの実行時間を指していない可能性があるため、削除するオブジェクトのコピーをイテレータの代わりにラムダに渡します。ラムダからのアクセス違反がときどき発生します

ベクトルから特定のオブジェクトを削除するラムダを設定するより良い方法はありますか?そして、ここでアクセス違反の正確な原因は何ですか?このエラー時にデバッグすると、ローカル変数とオート変数がnull /壊れているのでデバッグが難しくなります。

... std::vector<CustomLayout> customLayouts; // private class member variable 

void App::loadCustomLayouts() { 
    CustomLayout customLayout; 
    // ... create HWND 

    onMessage(WM_RBUTTONDOWN, [customLayout, this]() { 

     auto it = std::remove(customLayouts.begin(), customLayouts.end(), customLayout); 
     customLayouts.erase(it); // occasionally causes access violation 
    }); 
} 
+0

消去する前に 'it!= customLayouts.end()'をチェックしてみてください。そうであれば、 'customLayout'が' customLayouts'に見つかりませんでした。これは、あなたの問題の原因を手掛かりにするかもしれません。 – Mankarse

答えて

0

のstd :: customLayoutに等しいすべての値が削除された範囲の終了イテレータを返す取り除きます。実際には何も削除されません。要素の位置が変更されるだけで、新しい範囲の最後のイテレータの後に「削除された」要素が配置されます。それにもかかわらず、 "削除された"要素の状態は不特定であり、それらを参照することは問題を引き起こすかもしれない。

次に、STL end iteratorでは、最後の要素自体ではなく、範囲の最後の要素の次の要素を指します。そのため、イテレータの終了(あなたの場合はit)の操作は無効です。

customLayoutsには、customLayoutに等しい要素が含まれていない場合が考えられます。次に、itは決して存在しなかった要素を指し、eraseはそれを破壊しようとします。

eraseを新しい(より短い)範囲の最後の要素にする場合は、customLayouts.erase(it - 1);と書く必要があります。

+0

あなたの答えに感謝します。私はあなたのソリューションの部分をかなり理解していません。原因があなたが言うものなら、 'if(it!= customLayouts.end()){customLayouts.erase(it-1); } '回避する/修正する? –

+0

@ JakeMこれは動作するはずですが、例外は '-1'を省略すべきです。 – md5i

+0

@ JakeMこれはあなたが達成しようとしていることによって異なります。あなたは削除したいオブジェクトを書きませんでしたので、あなたが尋ねたようにあなたのコードの問題を指摘しました。おそらくあなたがコメントに書いた条件は、何も消されなければ手の届かない短いベクトルの最後の要素を残すので、あなたが得たいものではないでしょう。ベクタを紙に描き、ベクトルを再描画して不要な要素を横切ってコードを手動で「実行」してみてください。それはあなたが必要とするものを理解するのに役立ちます。 – Sergey

2

あなたは適切なremoveイディオムに従っていません。それは簡単です:

vec.erase(std::remove_if(vec.begin(), vec.end(), elem), vec.end()); 

何かを引いたり、カスタムブランチを行う必要はありません。

関連する問題