문제

모두가 알고 있듯이, 비주얼 C++ 런타임은 0이 아닌 특수 마커를 사용하여 초기화되지 않았거나 방금 해제된 메모리 블록을 표시합니다.초기화되지 않은 모든 메모리를 수동으로 0으로 설정하지 않고 이 동작을 완전히 비활성화할 수 있는 방법이 있습니까?null이 아닌 유효한 검사로 혼란을 겪고 있습니다. 0xFEEEFEEE != 0.

흠, 아마도 좀 더 잘 설명해야 할 것 같습니다.(new를 통해) 변수를 생성하고 초기화했는데 모든 것이 잘 진행되었습니다.삭제를 통해 해제하면 포인터가 다음으로 설정됩니다. 0xFEEEFEEE 대신에 NULL.적절한 수표를 삽입하면 NULL, 자체 메모리를 관리하는 모든 좋은 프로그램이 그렇듯, 나는 다음과 같은 문제를 제기합니다. 0xFEEEFEEE 통과하다 NULL 문제없이 확인하세요.모든 포인터를 수동으로 설정하는 것 외에 다른 좋은 방법이 있습니까? NULL 삭제할 때 메모리가 이미 해제되었는지 감지하려면?나는 사용하지 않는 것을 선호합니다 후원 단순히 오버헤드가 작더라도 원하지 않기 때문입니다. 그것이 제가 Boost를 사용하는 유일한 목적이기 때문입니다.

도움이 되었습니까?

해결책

의 책임이 아니다 delete 객체에 대한 모든 포인터를 재설정하려면 NULL.또한 Windows DEBUG 런타임에 대한 기본 메모리 채우기를 변경해서는 안 되며 다음과 같은 것을 사용해야 합니다. boost::shared_ptr<> 어떤 식 으로든 포인터를 위해.

즉, 정말로 원한다면 네 발에 총을 쏘아라 당신은 할 수 있습니다.

당신은 할 수 있습니다 변화 그만큼 기본 채우기 창문용 디버그 런타임 이와 같은 할당자 후크를 사용하면 됩니다.이것은 HEAP 할당 객체에서만 작동합니다!

int main(int argc,char** arv)
{
  // Call first to register hook    
  _CrtSetAllocHook(&zero_fill);
  // Do other stuff
  malloc(100);
}


int zero_fill(int nAllocType, 
              void* pvData, 
              size_t nSize,
              int nBlockUse, 
              long lRequest, 
              const unsigned char *szFileName, 
              int nLine )
{
  /// Very Importaint !! 
  /// infinite recursion if this is removed !!
  /// _CRT_BLOCK must not do any thing but return TRUE
  /// even calling printf in the _CRT_BLOCK will cause
  /// infinite recursion
  if ( nBlockUse == _CRT_BLOCK )
    return( TRUE );
  switch(nAllocType)
  {
  case _HOOK_ALLOC:
  case _HOOK_REALLOC:
    // zero initialize the allocated space.
    memset(pvData,0,nSize);
    break;
  case _HOOK_FREE:
    break;
  }
  return TRUE;
}

다른 팁

포인터를 생성할 때 명시적으로 초기화하십시오. NULL.마찬가지로 delete.초기화되지 않은 데이터의 값에 따라(몇 가지 특정 경우 제외) 문제가 발생할 수 있습니다.

스마트 포인터 클래스(예: boost::shared_ptr) 포인터 초기화 여부를 자동으로 처리합니다.

VC++의 동작은 어떤 사용자에게도 혼란을 야기해서는 안 됩니다. 유효한 당신이 할 수 있는지 확인하십시오.0xfeeefeee가 표시된다면 메모리에 쓰지 않았거나 메모리를 해제한 것이므로 어쨌든 메모리에서 읽어서는 안 됩니다.

초기화되지 않은 메모리를 읽고 있다면 검사 내용이 "유효"하지 않은 것이 확실합니다.메모리가 해제됩니다.이미 다른 용도로 사용 중일 수도 있습니다.C/C++에서는 초기화되지 않은 메모리의 내용에 대해 어떤 가정도 할 수 없습니다.

Java(및 C#)는 사용 전에 할당된 메모리가 0이 되도록 보장하며, 물론 가비지 수집으로 인해 해제된 메모리가 전혀 표시되지 않습니다.그러나 이는 메모리를 직접 노출하는 C 힙의 속성이 아닙니다.

디버그 모드 대신 릴리스 모드로 빌드하는 경우 런타임은 초기화되지 않은 메모리를 전혀 채우지 않지만 여전히 0이 되지는 않습니다.그러나, 당신은해야 ~ 아니다 이 동작에 따라 달라집니다. memset(), ZeroMemory() 또는 SecureZeroMemory()를 사용하여 직접 메모리를 명시적으로 초기화하거나 메모리가 아직 초기화되지 않았음을 나타내는 플래그를 어딘가에 설정해야 합니다.초기화되지 않은 메모리를 읽으면 정의되지 않은 동작이 발생합니다.

당신은 말한다:

(new를 통해) 변수를 생성하고 초기화했는데 모든 것이 잘 진행되었습니다.삭제를 통해 해제하면 포인터가 NULL 대신 0xFEEEFEEE로 설정됩니다.자체 메모리를 관리하는 모든 좋은 프로그램과 마찬가지로 NULL에 대한 적절한 검사를 삽입하면 0xFEEEFEEE가 문제 없이 NULL 검사를 통과하므로 문제가 발생합니다.

MSVC의 디버그 힙 루틴조차도 바늘 삭제 중 - 삭제하려는 포인터의 값은 변경되지 않습니다(심지어 NULL로도).방금 삭제한 개체에 속한 포인터에 액세스하는 것 같습니다. 이는 단순하고 단순한 버그입니다.

나는 당신이하려는 일이 잘못된 메모리 액세스를 단순히 은폐할 것이라고 확신합니다.실제로 무슨 일이 일어나고 있는지 보여주기 위해 코드 조각을 게시해야 합니다.

@제프 허바드(논평):

이것은 실제로 내가 원하는 솔루션을 실수로 제공합니다._HOOK_FREE에서 pvData를 NULL로 설정할 수 있으며 포인터 주소에 대해 0xFEEEFEEE 문제가 발생하지 않습니다.

이것이 효과가 있다면 이는 NULL 포인터를 테스트할 때 해제된 메모리를 읽고 있다는 의미입니다(즉, 포인터 자체가 해제된 메모리에 상주합니다).

이것은 버그입니다.

당신이 사용하고 있는 '솔루션'은 버그를 수정하는 것이 아니라 단순히 숨기는 것입니다.해제된 메모리가 다른 것에 할당되면 갑자기 잘못된 값을 잘못된 항목에 대한 포인터로 사용하게 됩니다.

이는 디버거에서 포인터에 대해 할당되지 않은 메모리를 볼 수 있게 해주기 때문에 실제로 VC++(그리고 다른 컴파일러에도 있다고 생각합니다)의 아주 좋은 기능입니다.해당 기능을 비활성화하기 전에 다시 한 번 생각해 보겠습니다.C++에서 객체를 삭제할 때 포인터를 다음으로 설정해야 합니다. NULL 나중에 개체를 다시 삭제하려고 시도하는 경우를 대비하여.이 기능을 사용하면 포인터를 설정하는 것을 잊어버린 장소를 찾아낼 수 있습니다. NULL.

릴리스 모드에서 작동하는 경우 전단 행운 때문입니다.

Mike B는 디버그 수정이 버그를 숨기고 있다고 가정하는 것이 옳습니다.릴리스 모드에서는 해제되었지만 다음으로 설정되지 않은 포인터가 사용되고 있습니다. NULL, 그리고 그것이 가리키는 메모리는 여전히 "유효"합니다.미래의 어느 시점에서는 메모리 할당이 변경되거나 메모리 이미지가 변경되거나 무언가로 인해 "유효한" 메모리 블록이 "유효하지 않게" 됩니다.이 시점에서 릴리스 빌드가 실패하기 시작합니다.디버그 모드가 "수정"되었기 때문에 문제를 찾기 위해 디버그 모드로 전환하는 것은 쓸모가 없습니다.

나는 우리 모두가 다음 코드가 작동하지 않아야 한다는 데 동의한다고 생각합니다.

char * p = new char[16];     // 16 bytes of random trash
strcpy(p, "StackOverflow");  // 13 characters, a '\0' terminator, and two bytes of trash
delete [] p;                 // return 16 bytes to the heap, but nothing else changes;

if (p != NULL)               // Why would p be NULL?  It was never set to NULL
    ASSERT(p[0] == 'S');     // In debug, this will crash, because p = 0xfeeefeee and 
                             // dereferencing it will cause an error.
                             // Release mode may or may or may not work, depending on
                             // other memory operations

다른 모든 포스터에서 말했듯이 포인터는 다음과 같이 설정되어야 합니다. NULL 전화 후 delete.스스로 할 것인지, 부스트나 다른 래퍼를 사용할 것인지, 아니면 이 스레드의 매크로를 사용할 것인지는 당신에게 달려 있습니다.

일어나는 일은 디버그 컴파일에서 내 코드 충돌이지만 릴리스 컴파일에서 성공합니다.

릴리스 빌드가 고객 컴퓨터에서 충돌합니다.항상 그렇습니다.

디버거 아래에서 확인했고 삭제에 전화 한 후 포인터가 0xfeeefeee로 설정됩니다.

포인터 삭제를 호출한 후에도 변경되지 않습니다.그들이 가리키는 메모리는 0xfeeefeee, 0xfeeefeee, ..., 0xfeeefeee로 설정됩니다.

프로그램이 해제된 메모리(DEBUG 빌드에서 0xfeeefeee 패턴으로 편리하게 표시됨)에서 데이터를 읽는 것을 발견하면 버그가 있는 것입니다.

@[제프 허바드]:

무슨 일이 일어나고 있는지, 디버그 컴파일에서는 내 코드가 충돌하지만 릴리스 컴파일에서는 성공합니다.디버거에서 확인했는데 포인터가 다음으로 설정되었습니다. 0xFEEEFEEE 삭제를 호출한 후.다시 말하지만, 릴리스 시 동일한 코드가 충돌하지 않고 예상대로 작동합니다.

이것은 매우 이상한 동작입니다. 저는 여전히 잠재적인 버그가 숨겨져 있을 것이라고 확신합니다. _CrtSetAllocHook() 해결 방법.

그만큼 0xFEEEFEEE 서명은 OS 힙 관리자가 해제된 메모리를 나타내는 데 사용됩니다(참조: http://www.nobugs.org/developer/win32/debug_crt_heap.html).혹시 재현 코드를 게시하고 사용 중인 컴파일러 버전을 정확히 표시할 수 있습니까?

여기서는 Visual Studio 기본값을 비활성화할 수 없다고 확신합니다. 비활성화하더라도 값은 메모리가 할당되기 전에 메모리에 있었던 것과 동일할 것입니다.

처음에 0으로 설정하는 습관을 들이는 것이 가장 좋습니다. 추가 문자는 2개뿐입니다.

int *ptr=0;

0으로 정의된 NULL 매크로를 사용할 수도 있지만 기본값은 아니므로 windows.h와 같은 항목을 포함하고 직접 정의할 때 여러 정의에 주의하세요!

malloc을 사용하는 경우 메모리를 어떤 것으로도 초기화하지 않습니다.당신은 무엇이든 얻을 수 있습니다.블록을 할당하고 0으로 초기화하려면 초기화만 포함된 malloc과 유사한 'calloc'을 사용하세요(malloc을 에뮬레이션하려는 경우 1로 설정하는 요소 크기 매개변수).약간의 차이가 있으므로 사용하기 전에 calloc을 읽어야 합니다.

http://wiki.answers.com/Q/What_is_the_difference_between_malloc_and_calloc_functions

나만의 #define을 만들고 사용하는 습관을 들이는 것은 어떨까요?

즉.

#define SafeDelete(mem) { delete mem; mem = NULL; }
#define SafeDeleteArray(mem) { delete [] mem; mem = NULL; }

물론 원하는 대로 이름을 지정할 수 있습니다.deleteZ, deletesafe 등 원하는 대로 선택하세요.

메모리 관리자를 만들 수도 있습니다.그런 다음 new 및 delete를 재정의하여 미리 할당된 메모리 척을 가져오거나 되돌릴 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top