std::list 删除在指针上调用删除?

发布于 2024-09-11 16:40:56 字数 1319 浏览 14 评论 0 原文

由于我无法弄清楚的段错误,我在程序上运行了 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 是否会使迭代器无效?

I ran valgrind on my program because of a segfault I can't figure out. It detected a problem here...

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)

The removal is in this method...

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 );
  }
} 

I didn't think removing a pointer from a list would call delete on it. What looks suspect here? If you need more information let me know.

P.S. Previously when debugging this, I noticed the problem occured because GetTileX and GetTileY weren't valid indices, and would return ridiculous numbers like 13775864. I think this is related to the delete issue though, and the removal or push_back is causing the problem.

Edit: Here is another code snippet

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 );
    }
  }
}

Could AdjustGridCoord be invalidating the iterator?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

無處可尋 2024-09-18 16:40:56

针对您的编辑,是的,我认为您的诊断是正确的。

您的代码有点令人困惑(主要是因为您将名称 obj 指定给对象指针和引用列表中其单元格的迭代器),但是这一行:

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

您删除了 obj 对象将使调用函数中的 obj 迭代器失效。正如您从 valgrind 输出中看到的,删除对象会导致列表删除保存对象指针的单元格,这就是 obj 迭代器所引用的内容。因此,obj迭代器无效。然后,当调用返回时,接下来发生的事情是循环增量:

++obj

这里,obj 是迭代器,它刚刚失效,并且在对 AdjustGridCoord< 的调用中删除了其引用单元​​格。 /代码>。这会导致对已释放内存的访问,这就是 valgrind 所抱怨的。

您基本上有两个选择:

  1. 重新构造循环,以便在调用 AdjustGridCoord 之前获得后续迭代器
  2. 迭代列表一次并记录需要进行的更改一些其他数据结构,然后对该辅助“更改列表”结构进行第二次循环,并在该循环中实际对原始列表进行这些更改。

2 的一个例子是创建一个 std::vector 。 > 保存您需要调用 AdjustGridCoord 的坐标,然后对其进行迭代以实际进行调用。

In response to your edit, yes, I think you have diagnosed it correctly.

Your code is a bit confusing (mainly because you give the name obj to both an object pointer and the iterator referring to its cell in the list), but this line:

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

where you remove the obj object will invalidate the obj iterator in the calling function. As you can see from the valgrind output, removing the object cause the list to delete the cell holding the object pointer, which is what the obj iterator refers to. Thus, the obj iterator is invalidated. Then, when the call returns, the very next thing that happens is the loop increment:

++obj

Here, obj is the iterator, which was just invalidated and its referent cell deleted within the call to AdjustGridCoord. This causes an access to memory that was deallocated, which is what valgrind is complaining about.

You essentially have two options:

  1. Re-structure your loop so that you get the subsequent iterator before you call AdjustGridCoord
  2. Iterate through the list once and record what changes you need to make in some other data structure, and then do a second loop over that secondary "change list" structure, and within that loop actually make those changes to the original list.

An example of 2 would be to create a std::vector<std::pair<unsigned int, unsigned int> > that holds the coordinates that you need to call AdjustGridCoord on, and then iterate over that to actually make the calls.

余厌 2024-09-18 16:40:56

释放的大小为 12 的块实际上是列表节点,而不是您的对象。因此,std::list::remove() 并未对指针调用 delete,它只是删除包含它的列表节点。

我无法从您的代码片段中看出您实际上(错误地)使用了该内存的位置。

The block of size 12 free'd is actually the list node, not your object. So, std::list::remove() didn't call delete on your pointer, it simply deleted the list node containing it.

I can't tell from your code snippets where you actually (wrongly) use that memory.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文