20

std :: map :: clear()の奇妙な振る舞いを観察しています。このメソッドは、呼び出されたときに要素のデストラクタを呼び出すことになっていますが、clear()を呼び出した後もメモリにアクセスできます。

例えば:

struct A
{
  ~A() { x = 0; }
  int x;
};

int main( void )
{
  std::map< int, A * > my_map;
  A *a = new A();
  a->x = 5;
  my_map.insert( std::make_pair< int, *A >( 0, a ) );

  // addresses will be the same, will print 5
  std::cout << a << " " << my_map[0] << " " << my_map[0]->x << std::endl;

  my_map.clear();

  // will be 0
  std::cout << a->x << std::endl;

  return 0;
}

a問題は、そのデストラクタがmap :: clear()によって呼び出された後でも、なぜ変数にアクセスできるのかということです。delete a;呼び出し後に書き込む必要がありますか、それともmy_map.clear()内容を上書きしても安全aですか?

よろしくお願いします、sneg

4

6 に答える 6

23

マップ(またはリストなど)にポインターを格納する場合、マップはポインターがnewで作成されたかどうかを認識しないため、ポインターを削除する責任はユーザーにありますclear関数は、ポインターを使用しない場合にのみデストラクタを呼び出します。

ああ、もう1つ、デストラクタを呼び出す(またはdeleteを呼び出す)ことは、メモリにアクセスできなくなることを意味するわけではありません。これは、アクセスした場合にゴミにアクセスすることを意味するだけです。

于 2009-02-20T10:53:24.197 に答える
19

std::map は、ポインター値が指すメモリーを管理しません。自分で行うのはあなた次第です。スマート ポインターを使用したくない場合は、次のような汎用の free & clear 関数を記述できます。

template <typename M> void FreeClear( M & amap ) 
    for ( typename M::iterator it = amap.begin(); it != amap.end(); ++it ) {
        delete it->second;
    }
    amap.clear();
}

そしてそれを使用します:

std::map< int, A * > my_map;
// populate
FreeClear( my_map )

;

于 2009-02-20T11:07:07.240 に答える
4

これmap.clear()は、マップに含まれているデータ(この場合は、へのポインタ)のデストラクタを呼び出すためaです。そして、これは何もしません。

占有されているメモリを自動的に再利用するために、ある種のスマートポインタをマップに配置することをお勧めします。a

ところで、なぜあなたはへの呼び出しにテンプレート引数を入れるのmake_pairですか?テンプレート引数の推論は、ここではかなりうまくいくはずです。

于 2009-02-20T10:56:14.923 に答える
1

ヒープ メモリの一部を解放しても、その内容はゼロになりません。それらは、再び割り当てられるだけです。もちろん、割り当てられていないメモリにアクセスした場合の影響は未定義であるため、アクセスできないメモリを考慮する必要があります。

メモリ ページへのアクセスを実際に防止するのは下位レベルで行われ、std ライブラリはそれを行いません。

new でメモリを割り当てるときは、スマート ポインタを使用しない限り、自分でメモリを削除する必要があります。

于 2009-02-20T11:09:03.973 に答える
0

任意のコンテナーにオブジェクトの Type が格納され、対応するコンストラクターが呼び出されます。各ノードの内部コードは次のようになります。

__NodePtr
{
    *next;
    __Ty    Val;
}

割り当てるときは、タイプに基づいて val を構築してからリンクすることによって行われます。次のようなもの:

_Ty _Val = _Ty();
_Myhead = _Buynode();
_Construct_n(_Count, _Val);

削除すると、対応するデストラクタが呼び出されます。

参照 (ポインター) を格納すると、コンストラクターは呼び出されず、破棄されません。

于 2009-02-20T11:18:17.103 に答える