2010-07-29 4 views
3

나는 프로그램에서 segfault 때문에 valgrind를 실행했습니다. 알아낼 수 없기 때문입니다. 그것은 여기에 문제가 ...std :: list는 포인터에서 호출 삭제를 제거합니까?

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을 부를 것이다 목록에서 포인터를 제거 생각하지 않았다를 발견했습니다. 여기에 의심되는 것? 더 많은 정보가 필요하시면 알려주십시오.

P. 이전에 이것을 디버깅 할 때 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 수있다?

+0

'가정'은 ** 모든 위험한 **입니다. _ "목록에서 포인터를 지우면 delete가 호출 될 것이라고 생각하지 않았습니다."_ _ 항상 오류 처리 방법을 시도하는 것보다 실제로 무엇을하는지 배우는 것을 선호합니다. –

+2

그것은 정말로 가정이 아니 었습니다. 목록에서 무언가를 제거하면 객체의 소멸자가 호출되고 포인터가없는 경우에는 사실이 아닌가? – lotad

+1

오른쪽 포인터는'delete' 연산을 수행하지 않습니다. 이 오류는 목록에 없지만 어딘가에서 사용할 수 있습니다. – GManNickG

답변

2

귀하의 편집에 대한 응답으로 예, 올바르게 진단했다고 생각합니다.

귀하의 코드는 혼란을 조금 있지만,이 선 (당신이 이름을 제공 주로하기 때문에 객체 포인터와 목록에서 해당 셀에 참조 반복자 모두 obj) :

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

것은 당신이 제거 obj 개체는 호출 함수에서 obj 반복자를 무효화합니다. valgrind 출력에서 ​​볼 수 있듯이 객체를 제거하면 목록에서 객체 포인터가있는 셀을 삭제합니다. 이는 obj 반복기가 참조하는 것입니다. 따라서 반복자 obj이 유효하지 않습니다. 호출이 반환이 발생 바로 다음 일이 루프 증가 때 그런 다음, 다음은

++obj 

, objAdjustGridCoord에 전화에서 삭제 된 단지 무효화 된 반복자, 그 지시 대상 세포이다. 이로 인해 valgrind가 불평하는 메모리 할당이 해제 된 메모리가 액세스됩니다. 당신은 당신이 한 번 목록을 AdjustGridCoord

  • 반복 처리를 호출하고 당신이해야 할 어떤 변화 기록 하기 전에 다음의 반복자를 얻을 수 있도록 다시 구조

    1. 루프 :

      당신은 기본적으로 두 가지 옵션이 있습니다 어떤 다른 데이터 구조에서는 두 번째 루프를 두 번째 "변경 목록"구조로 처리하고 그 루프 내에서 실제로 원래의 목록을 변경합니다.

    2의 예는 당신이 AdjustGridCoord를 호출 할 필요가 좌표를 보유하는 std::vector<std::pair<unsigned int, unsigned int> >를 만든 다음 사실로 통화를 할 것을 반복하는 것입니다.

  • +0

    다른 옵션 : ListItr을 AdjustGridCoord로 전달하고 완료되면 ListItr을 다음 객체로 반환하도록합니다. 객체를 제거해야하는 경우 std :: list :: erase()를 호출하고 반환 된 반복자를 반환합니다. 그렇지 않으면, 증가 된 반복자를 리턴한다. –

    1

    크기 12의 블록은 실제로는 객체가 아닌 목록 노드입니다. 따라서 std::list::remove()은 포인터에 delete을 호출하지 않았습니다.이 포인터를 포함하는 목록 노드는 delete입니다.

    실제로 메모리를 잘못 (잘못) 사용하는 코드 스 니펫에서 알 수 없습니다.