プロジェクトには、メッセージ イベントを順番に処理するために std::queue を使用するという要件があります。
簡単な例は次のとおりです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
テスト ケースでは、合計 3 つのオブジェクトをキュー my_event_queue にプッシュし、while ループとフロント ループを使用してキュー内のオブジェクトのアドレスを取得してポップしました。
問題は、my_event の削除にあります。理論的には、std::queue はオブジェクトの破棄には関与しません。つまり、新しいオブジェクトはそれ自体で削除する必要があるため、オブジェクトをポップアウトするたびに削除します。
その後、while ループが 2 回目に到達したときにアボートが発生したため、メモリを見てみると、2 回目の削除時のメモリが未割り当てであったため、アボートが発生しました。
スクリーンショットからわかるように、ハンドルのサイズは 4 バイトであるため、赤枠 3 つの領域にメモリ領域が割り当てられており、削除のたびに 4 バイトのメモリ領域が消去されるはずです。つまり、1回目は1番目の赤枠を消し、2回目は2番目の赤枠を消します。
しかし実際には、最初の削除でメモリ長の 20 バイトが消去され、その結果、2 回目の削除で未割り当てメモリにアクセスすることになりました。
その後の調査により、プッシュ時にポインタの代わりに値が渡されたため、std::queue がコピー コンストラクタを呼び出すことが原因であることがわかりました (コピー コンストラクタが明示的に定義されていない場合は、デフォルトのコンストラクタが呼び出されます)。実際には保存されたコピーです。
ポップするたびに、コピーはアクティブに破棄され、オントロジーには影響しません (手動で削除する必要があります)。そのため、コピーのポインタを取得し、ポップ後に削除するだけです。このときのアドレスは次のとおりです。すでにダングリング ポインタです。動作は未定義です
20 バイトがキューのデフォルトのサイズであることに注意してください。
どうやって解決すればいいでしょうか?
事前に配列を宣言しておき、その中に new の後のアドレスを入れておき、最後に使用した後に順番に削除することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
当然更好的办法是使用智能指针来保证自动释放内存 std::queue<std::unique_ptr<MyEvent>> my_event_queue;
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|