3

理解できないセグメンテーション違反のため、プログラムでvalgrindを実行しました。ここで問題が検出されました...

Address 0x75c7670 is 0 bytes inside a block of size 12 free'd
  at 0x4024851: operator delete(void*) (vg_replace_malloc.c:387)
  by 0x805F6D8: std::list<Object*, std::allocator<Object*>::remove(O
  bject* const&) (new_allocator.h:95)

除去はこの方法で行われます...

void ObjectManager::AdjustGridCoord( int x, int y, Object* const obj ) {
  // GetTileX and GetTileY guaranteed to be valid indices
  int newX = ObjectAttorney::GetTileX( obj );
  int newY = ObjectAttorney::GetTileY( obj );
  if ( x != newX || y != newY  ) {
    m_objGrid[x][y].remove( obj );
    m_objGrid[newX][newY].push_back( obj );
  }
} 

リストからポインタを削除しても、ポインタが必要になるとは思いませんでしdeleteた。ここで何が疑わしいですか?さらに詳しい情報が必要な場合はお知らせください。

PS以前、これをデバッグしたときに、GetTileXとGetTileY有効なインデックスではなく、13775864のようなばかげた数値を返すために問題が発生したことに気付きました。ただし、これは問題に関連していると思いますdelete。削除またはpush_backが問題の原因です。

編集:これは別のコードスニペットです

for ( unsigned int x = 0; x < m_objGrid.size(); ++x ) {
  for ( unsigned int y = 0; y < m_objGrid[x].size(); ++y ) {
    for ( ListItr obj = m_objGrid[x][y].begin(); obj != m_objGrid[x][y].end(); ++obj ) {
      ObjectAttorney::UpdateAI( *obj );
      AdjustGridCoord( x, y, *obj );
    }
  }
}

AdjustGridCoordがイテレータを無効にしている可能性がありますか?

4

2 に答える 2

2

あなたの編集に応えて、はい、あなたはそれを正しく診断したと思います。

コードは少し混乱しますが(主にobj、オブジェクトポインターと、リスト内のセルを参照するイテレーターの両方に名前を付けるため)、次の行になります。

m_objGrid[x][y].remove( obj );

objオブジェクトを削除するobjと、呼び出し元の関数のイテレータが無効になります。valgrindの出力からわかるように、オブジェクトを削除すると、リストはオブジェクトポインターを保持しているセルを削除します。これは、objイテレーターが参照するものです。したがって、objイテレータは無効になります。次に、呼び出しが戻ると、次に発生するのはループの増分です。

++obj

objこれは、の呼び出し内で無効化され、その参照セルが削除されたイテレータですAdjustGridCoord。これにより、割り当てが解除されたメモリへのアクセスが発生します。これは、valgrindが不満を言っていることです。

基本的に2つのオプションがあります。

  1. 呼び出すに後続のイテレータを取得できるように、ループを再構築しますAdjustGridCoord
  2. リストを1回繰り返し、他のデータ構造に必要な変更を記録してから、その2番目の「変更リスト」構造に対して2番目のループを実行し、そのループ内で実際に元のリストに変更を加えます。

2の例は、std::vector<std::pair<unsigned int, unsigned int> >呼び出す必要のある座標を保持するを作成AdjustGridCoordし、それを繰り返して実際に呼び出すことです。

于 2010-07-30T00:21:20.620 に答える
1

サイズ12の解放されたブロックは、実際にはリストノードであり、オブジェクトではありません。したがって、ポインタをstd::list::remove()呼び出さずdeleteに、ポインタdeleteを含むリストノードを呼び出すだけです。

コードスニペットから、実際に(間違って)そのメモリをどこで使用しているかわかりません。

于 2010-07-29T23:07:52.307 に答える