1

今日、私はこの質問をしました。

この問題の調査に時間を費やした後、何が起こっているのかを発見しました。別の問題として追跡するのに十分興味深いと思うので、これを新しい質問として投稿しています。その質問を回答(およびこれへのリンク)で更新します。

デバッガーからの単体テストの起動

// Construct object
Object* pObject = new Object(...);
// Pointer value of pObject == 0x05176960

// Lots of other code
// ...

// Destroy object
delete pObject;

// Construct object again
pObject = new Object(...);
// Pointer value of pObject == 0x05560194     /* Different memory location */

コマンドラインから単体テストを起動する

// Construct object
Object* pObject = new Object(...);
// Pointer value of pObject == 0x05176960

// Lots of other code
// ...

// Destroy object
delete pObject;

// Construct object again
pObject = new Object(...);
// Pointer value of pObject == 0x05176960     /* Same memory location */

要約すれば:

  • コマンド ラインから単体テストを起動すると、 (新しいものを割り当てる前に前のものを)newを割り当てるための後続の呼び出しは、常にメモリ内の同じアドレスを返します。ObjectdeleteObject
  • デバッガーから単体テストを起動すると、 (新しいものを割り当てる前に前のものを)newを割り当てるための後続の呼び出しは、常にメモリ内の一意のアドレスを返します。ObjectdeleteObject

問題は、コマンド ラインから起動すると、 の割り当ては常にメモリ内で同じアドレスを取得するため、古いObjectポインターを格納しているアクセス中のマップを引き続き使用でき、テストがクラッシュしないことです。しかし、欠陥の修正が行われていないときに単体テストをクラッシュさせて、黙って失敗したり、欠陥が再発したりしないようにしたいと考えています。

私の質問には2つの部分があります:

  1. コマンド ラインから単体テストを起動すると、ヒープ マネージャーがメモリの同じ部分を再利用するのに、デバッガーから単体テストを起動すると再利用しないのはなぜですか?

  2. 単体テストを正しく記述できるようにするために、テスト ハーネスで使用できるコンパイラ設定、または削除したメモリのセクションをヒープ マネージャーが再利用するのを防ぐために呼び出すことができるメソッドはありますか? 1


1明らかにこれを行う 1 つの方法は、元のオブジェクトを削除しないことですが、これを割り当てるコードの一部は私の運用コードにあり、これを行うとメモリ リークが発生します。

4

4 に答える 4

2

new必要な動作をdeleteする独自のバージョンに置き換えることができます。

于 2010-11-25T05:56:35.910 に答える
2

未定義の動作に依存しているため、単体テストに欠陥があります。単体テストを書き直して、未定義の動作に依存しないようにする必要があります。未定義の動作に依存しないようにする必要があります。その場合、メモリ マネージャーがメモリの割り当てを決定する方法に関係なく、常に合格します。

あなたがやっていることはこれです:

Object* pObject = new Object(...);
...
delete pObject;
pObject = new Object(...);
// Use dangling pointer to first object, and if it crashes, the unit test fails
// This is WRONG since a crash isn't guaranteed

代わりに、次のように機能するように単体テストを再構築する必要があります。

Object* pObject = new Object(...);
...
// Check to see if there are dangling references to pObject right before we
// delete it.  If there are, assert() and fail the unit test.
assert(NoDanglingReferences(pObject));
delete pObject;
// Continue on with more tests
于 2010-11-25T06:04:37.257 に答える
1

まず第一に、「通常の」メモリマネージャーではありません。メモリの割り当てを解除すると、その所有権がメモリ マネージャーに渡され、後者はそれを再利用できます。

ユーザー Andreas Brinckが示唆するように、カスタム マネージャーを作成することもできますが、それは何をするでしょうか? 空気からメモリを作成するのではなく、CRT ヒープやオペレーティング システム ヒープなどからメモリを要求します。

シナリオ A. 基になるヒープにメモリが返されない - リークが発生し、メモリ ブロックはアドレス空間にマップされたままになり、アクセス可能になります。

シナリオ B. 基になるヒープにメモリを返します。その後、管理者がメモリを再度割り当てようとすると、基になるヒープがそのブロックを再度返すことができます。また、メモリをヒープに戻すときに、基になるヒープが何をするかわかりません。マップされていないかどうかにかかわらず、そのメモリへのアクセスはクラッシュするかどうかにかかわらず可能性があります。

肝心なのは、あなたがめちゃくちゃだということです。未定義の動作をテストしようとしても、あまり生産的ではありません。

于 2010-11-25T06:30:38.647 に答える
0

これは UNDEFINED BEHAVIOUR の例です。C++ もヒープ マネージャーも、メモリの割り当て方法を定義しません。メモリが再利用されているかどうかに依存することはできません。上記のようなことをすると、返されたポインタが最初に割り当てられたものと異なるかどうかを判断または変更する方法がありません。

于 2010-11-25T05:45:18.283 に答える