문제

나의 회사에있는 코딩하는 규칙을 말한다 확보 한 후,모든 메모리를 다시 설정 변수가 NULL.예를 들어...

void some_func () 
{
    int *nPtr;

    nPtr = malloc (100);

    free (nPtr);
    nPtr = NULL;

    return;
}

나는 느낌,그와 같은 경우에 표시된 코드는 위의 설정을 NULL 있지 않은 어떤 의미입니다.또는 나는 뭔가?

으면 의미가 없는 등의 경우에,내가 그것을 가진"품질팀은"이 코딩은 규칙이 있습니다.조언을 주시기 바랍니다.

도움이 되었습니까?

해결책

사용하지 않는 포인터를 NULL로 설정하는 것은 방어적인 스타일이며 매달려 포인터 버그로부터 보호합니다. 매달려있는 포인터가 해제 된 후에 액세스하면 무작위 메모리를 읽거나 덮어 쓸 수 있습니다. 널 포인터에 액세스하면 대부분의 시스템에서 즉시 충돌하여 오류가 무엇인지 즉시 알려줍니다.

로컬 변수의 경우, 해제 후 포인터에 더 이상 액세스하지 못한다는 것이 "명백한"경우 약간 무의미 할 수 있으므로이 스타일은 멤버 데이터 및 전역 변수에 더 적합합니다. 로컬 변수의 경우에도 메모리가 해제 된 후에 함수가 계속되면 좋은 접근 방식 일 수 있습니다.

스타일을 완성하려면 Pointers가 실제 포인터 값을 할당하기 전에 NULL로 초기화해야합니다.

다른 팁

포인터 설정 NULL ~ 후에 free 특허 적으로 허위 전제에 대한 "좋은 프로그래밍"규칙으로 종종 대중화되는 모호한 관행입니다. 그것은 "올바른"범주에 속하는 가짜 진실 중 하나이지만 실제로는 전혀 유용하지 않으며 때로는 부정적인 결과를 초래합니다.

의심 할 여지없이, 포인터를 설정합니다 NULL ~ 후에 free 동일한 포인터 값이 전달 될 때 끔찍한 "이중 자유"문제를 방지해야합니다. free 두 번 이상. 그러나 실제로 10 개 중 9 건에서 실제 "이중 자유"문제는 다른 동일한 포인터 값을 보유한 포인터 객체는 인수로 사용됩니다. free. 말할 것도없이, 포인터를 설정합니다 NULL ~ 후에 free 그러한 경우 문제를 예방하기 위해 절대적으로 아무것도 달성하지 못합니다.

물론, 인수와 동일한 포인터 객체를 사용할 때 "이중 자유"문제를 해결할 수 있습니다. free. 그러나 실제로 그런 상황에서는 일반적으로 실수로 "이중 무료"가 아니라 코드의 일반적인 논리 구조에 문제가 있음을 나타냅니다. 이러한 경우 문제를 처리하는 올바른 방법은 동일한 포인터가 전달 될 때 상황을 피하기 위해 코드 구조를 검토하고 다시 생각하는 것입니다. free 두 번 이상. 그러한 경우 포인터를 설정합니다 NULL 그리고 "고정 된"문제를 고려하는 것은 카펫 아래에서 문제를 쓸어 내려는 시도에 지나지 않습니다. 코드 구조의 문제는 항상 다른 방법을 찾을 수 있기 때문에 일반적으로 작동하지 않습니다.

마지막으로, 코드가 포인터 값에 의존하도록 특별히 설계된 경우 NULL 아니면 아니에요 NULL, 포인터 값을 NULL ~ 후에 free. 그러나 일반적인 "모범 사례"규칙 (항상 포인터를 설정하는 것과 같이 NULL ~ 후에 free") 다시 한번, 그것은 잘 알려진 꽤 쓸모없는 가짜이며, 종종 순전히 종교적이고 부두 같은 이유로 일부가 뒤 따릅니다.

대부분의 응답하지 못하도록 하는 것에 중점을 두고 두 무료이지만,설정 포인터가 NULL 로 또 다른 장점을 가지고 있으며.면 무료는 포인터는 메모리를 사용할 수 있는 재할당에 의해 다시 호출하는 malloc.는 경우 당신은 여전히 원래 포인터를 주변에 끝낼 수도 있습 응용 프로그램과 함께,당신이 시도하는 포인터를 사용하여 후유 및 손상된 어떤 다른 변수,그리고 당신의 프로그램으로 들어가 알 수 없는 상태이며 모든 종류의 나쁜 일이 일어날 수 있습니다(충돌 만약 당신이 운이 좋다면,데이터 손상이면 불길).당신이 설정한 포인터를 NULL 후,모든 시도는 읽기/쓰기를 통해 포인터가 나중에 결과에서 세그멘테이션,일반적으로 바람직한 임의의 메모리 손상입니다.

모두를 위한 이유,그것은 좋은 생각이 될 수 있습을터 NULL 후 무료().그것은 항상 필요합니다.는 경우,예를 들어,포인터 변수가 범위의 후 즉시 무료(),많지 않는 이유를 NULL 로 설정합니다.

이것은 메모리를 덮어 쓰는 것을 피하기위한 좋은 관행으로 간주됩니다. 위의 기능에서는 불필요하지만 종종 완료되면 응용 프로그램 오류를 찾을 수 있습니다.

대신 이와 같은 것을 시도하십시오.

#if DEBUG_VERSION
void myfree(void **ptr)
{
    free(*ptr);
    *ptr = NULL;
}
#else
#define myfree(p) do { void ** __p = (p); free(*(__p)); *(__p) = NULL; } while (0)
#endif

Debug_version을 사용하면 디버깅 코드에서 Freees를 프로파일 할 수 있지만 기능적으로 동일합니다.

편집하다: 추가 ... 아래에 제안 된대로 감사합니다.

무료 () D 인 포인터에 도달하면 파손되었는지 아닌지가 될 수 있습니다. 그 메모리는 프로그램의 다른 부분으로 재 할당 된 다음 메모리 부패를 얻을 수 있습니다.

포인터를 NULL로 설정하면 액세스하면 프로그램이 항상 segfault와 충돌합니다. 더 이상, 때로는 작동하지 않습니다. '', 더 이상, 예측할 수없는 방식으로 충돌이 발생합니다. 디버그하기가 더 쉽습니다.

포인터를 설정합니다 free'D 메모리는 포인터를 통해 해당 메모리에 액세스하려는 모든 시도가 정의되지 않은 동작을 일으키지 않고 즉시 충돌한다는 것을 의미합니다. 일이 어디에서 잘못되었는지 결정하는 것이 훨씬 쉬워집니다.

나는 당신의 주장을 볼 수 있습니다 : 이후 nPtr 바로 바로 범위를 벗어나고 있습니다 nPtr = NULL, 그것을 설정할 이유가없는 것 같습니다. NULL. 그러나 a struct 회원 또는 포인터가 즉시 범위를 벗어나지 않는 다른 곳에서는 더 의미가 있습니다. 포인터가 사용하지 말아야 할 코드로 다시 사용되는지 여부는 즉시 명백하지 않습니다.

개발자가이를 따르기 위해 규칙을 자동으로 시행하는 것이 훨씬 어렵 기 때문에이 두 경우를 구별하지 않고 규칙이 언급 될 수 있습니다. 포인터를 설정하는 것은 아프지 않습니다 NULL 모든 무료 후에는 큰 문제를 지적 할 가능성이 있습니다.

C에서 가장 일반적인 버그는 이중 무료입니다. 기본적으로 당신은 그런 일을합니다

free(foobar);
/* lot of code */
free(foobar);

그리고 그것은 꽤 나쁘게 만들어졌습니다. OS는 이미 해방 된 메모리를 해방 시키려고 노력하고 일반적으로 Segfault를 해방 시키려고합니다. 따라서 모범 사례는 설정하는 것입니다 NULL, 따라서 테스트를 하고이 메모리를 자유롭게 해야하는지 확인할 수 있습니다.

if(foobar != null){
  free(foobar);
}

또한 주목해야합니다 free(NULL) 아무것도하지 않으므로 if 문을 쓸 필요가 없습니다. 나는 실제로 OS 전문가는 아니지만 지금도 대부분의 OS는 더블 무료로 충돌 할 것입니다.

그것은 또한 쓰레기 수집 (Java, Dotnet)이있는 모든 언어 가이 문제가없고 개발자에게 메모리 관리를 전체적으로 떠나지 않아도 된 것을 자랑스럽게 생각한 주된 이유이기도합니다.

이것의 배후에있는 아이디어는 자유 포인터를 우발적으로 재사용하는 것입니다.

이것은 실제로 중요합니다. 메모리를 풀어 주지만 프로그램의 후반부는 공간에 착륙하는 새로운 것을 할당 할 수 있습니다. 오래된 포인터는 이제 유효한 메모리 덩어리를 가리 킵니다. 그런 다음 누군가가 포인터를 사용하여 유효하지 않은 프로그램 상태를 이끌어 낼 수 있습니다.

포인터를 무효화하면 사용하려는 시도는 0x0을 Dereference로 연결하여 바로 충돌하여 디버깅하기 쉽습니다. 임의의 메모리를 가리키는 임의의 포인터는 디버그하기가 어렵습니다. 분명히 필요하지는 않지만 모범 사례 문서에있는 이유입니다.

에서 ANSI C 표준:

void free(void *ptr);

무료 함수 공간 을 지적하여 서버를 할당, 즉,사용할 수 있는 추가 를 할당합니다.는 경우 ptr null 포인터 no action 가 발생합니다.그렇지 않은 경우, 인수와 일치하지 않은 포인터 이전의 반환에 의해 calloc, malloc,또는 realloc 능한 경우,또는 의 공간 할당 해제에 의해 전화 무료 또는 realloc,동작 가 정의되지 않습니다.

"정의되지 않은 행동"거의 항상 프로그램에 충돌이 발생합니다.그래서 같은 이를 방지하기 위해 안전하게 다시 설정에 대한 포인터 NULL 입니다.무료()자체할 수 없다 이렇게 그대로 전달되는 포인터만 아니 포인터를 포인터이다.를 작성할 수도 있습니다 더 안전한 버전 무료()는 Null 을 포인:

void safe_free(void** ptr)
{
  free(*ptr);
  *ptr = NULL;
}

사람들이 자유로운 메모리 할당에 액세스 할 때 내 경험에서와 같이 이것이 어딘가에 다른 포인터가 있기 때문에 거의 항상 도움이되지 않는다는 것을 알게됩니다. 그리고 "쓸모없는 혼란을 피하는"다른 개인 코딩 표준과 충돌하기 때문에 코드가 거의 도움이되지 않는다고 생각하기 때문에 그렇게하지 않습니다.

그러나 포인터를 다시 사용하지 않으면 변수를 NULL로 설정하지는 않지만 종종 더 높은 레벨 디자인은 어쨌든 NULL로 설정 해야하는 이유를 제공합니다. 예를 들어, 포인터가 클래스의 구성원이고 내가 가리키는 내용을 삭제 한 경우 "계약"을 삭제 한 경우 클래스를 좋아한다면 해당 멤버가 언제라도 유효한 것을 가리려면 NULL로 설정해야한다는 것입니다. 그런 이유로. 작은 구별이지만 나는 중요한 것입니다.

C ++에서는 항상 누구를 생각하는 것이 중요합니다. 소유합니다 이 데이터는 메모리를 할당 할 때 (스마트 포인터를 사용하지 않는 한, 심지어 생각이 필요하지 않은 경우). 이 과정은 포인터가 일반적으로 일부 클래스의 구성원이되는 경향이 있으며 일반적으로 클래스가 항상 유효한 상태에 있기를 원하며, 가장 쉬운 방법은 멤버 변수를 NULL로 설정하여 IT 지점을 표시하는 것입니다. 지금은 아무것도 없습니다.

일반적인 패턴은 모든 멤버 포인터를 생성자의 NULL로 설정하고 디자인이 해당 클래스가 말하는 데이터에 대한 모든 포인터에서 소멸자 호출을 삭제하도록하는 것입니다. 소유합니다. 분명히이 경우에는 이전 데이터를 소유하지 않았다는 것을 나타내는 것을 삭제할 때 NULL로 포인터를 설정해야합니다.

요약하자면, 나는 종종 무언가를 삭제 한 후 NULL에 대한 포인터를 설정했지만, 코딩 표준 규칙을 맹목적으로 따르기보다는 데이터를 소유 한 사람에 대한 더 큰 디자인과 생각의 일부입니다. 나는 당신의 예에서 그렇게하지 않을 것입니다. 나는 그렇게 할 수있는 이점이 없다고 생각하기 때문에 내 경험에 따라 버그와 나쁜 코드에 대한 책임이있는 "혼란"을 추가합니다.

최근에 나는 답을 찾은 후 같은 질문을 발견했습니다. 나는이 결론에 도달했다.

그것은 모범 사례이며, 모든 (임베디드) 시스템에서 휴대용을 만들기 위해 이것을 따라야합니다.

free() 라이브러리 함수로 플랫폼이 변경 될 때 다양 하므로이 기능에 대한 포인터를 전달한 후 메모리를 자유롭게 한 후이 포인터가 NULL로 설정 될 것으로 기대하지 않아야합니다. 플랫폼에 구현 된 일부 라이브러리의 경우에는 해당되지 않을 수 있습니다.

그래서 항상 가십시오

free(ptr);
ptr = NULL;

이 규칙은 다음 시나리오를 피하려고 할 때 유용합니다.

1) 복잡한 논리 및 메모리 관리로 기능이 정말 길며 기능의 나중에 삭제 된 메모리에 대한 포인터를 실수로 재사용하고 싶지 않습니다.

2) 포인터는 상당히 복잡한 동작을 가진 클래스의 멤버 변수이며 다른 기능에서 삭제 된 메모리에 대한 포인터를 실수로 재사용하고 싶지 않습니다.

시나리오에서는 그다지 의미가 없지만 기능이 더 길어지면 중요 할 수 있습니다.

NULL로 설정하면 실제로 로직 오류를 나중에 마스킹 할 수 있거나 유효하다고 가정 할 경우 여전히 NULL에 충돌하므로 중요하지 않습니다.

일반적으로, 나는 당신이 그것이 좋은 생각이라고 생각할 때 Null로 설정하는 것이 좋습니다. 그리고 그것이 가치가 없다고 생각할 때 귀찮게하지 않습니다. 대신 짧은 기능과 잘 설계된 수업을 작성하는 데 중점을 둡니다.

다른 말에 추가하기 위해, 포인터 사용의 좋은 방법 중 하나는 항상 유효한 포인터인지 아닌지를 확인하는 것입니다. 같은 것 :


if(ptr)
   ptr->CallSomeMethod();

해방 후 포인터를 NULL로 명시 적으로 표시하면 C/C ++에서 이러한 종류의 사용을 허용합니다.

이것은 모든 포인터를 null로 초기화하는 것이 더 많은 논쟁 일 수 있지만, 이와 같은 것은 매우 비열한 버그 일 수 있습니다.

void other_func() {
  int *p; // forgot to initialize
  // some unrelated mallocs and stuff
  // ...
  if (p) {
    *p = 1; // hm...
  }
}

void caller() {
  some_func();
  other_func();
}

p 이전과 같은 스택의 같은 장소에 있습니다. nPtr, 따라서 여전히 유효한 포인터가 포함될 수 있습니다. 할당 *p 모든 종류의 관련이없는 것들을 덮어 쓰고 추악한 버그로 이어질 수 있습니다. 특히 컴파일러가 디버그 모드에서 0으로 로컬 변수를 초기화하지만 최적화가 켜지지 않은 경우. 따라서 디버그 빌드에는 버그의 징후가 표시되지 않고 릴리스 빌드가 무작위로 폭발합니다 ...

방금 널에 해제 된 포인터를 설정하는 것은 필수가 아니라 좋은 관행입니다. 이런 식으로, 당신은 피할 수 있습니다.

NULL에 대한 포인터 설정은 소위 이중 무료를 다시 보호하는 것입니다. Free ()가 해당 주소의 블록을 재 할당하지 않고 동일한 주소에 대해 두 번 이상 호출되는 상황입니다.

이중 무료는 정의되지 않은 행동으로 이어집니다. 일반적으로 부패가 쌓이거나 즉시 프로그램을 충돌시킵니다. 널 포인터를 위해 무료 ()을 호출하는 것은 아무것도하지 않으므로 안전합니다.

따라서 Free ()가 해당 포인터를 NULL로 설정 해야하는 직후에 포인터가 스코프를 떠나지 않는 한 모범 사례는 Free ()가 다시 호출 되더라도 NULL 포인터와 정의되지 않은 동작이 필요합니다. 회피됩니다.

아이디어는 자유를 해제 한 후에도 밸리드 포인터를 해석하려고한다면 조용하고 신비롭게 대신 힘들지 않고 실패하고 싶다는 것입니다.

그러나 ... 조심하십시오. 모든 시스템이 널리 회의를 받으면 segfault를 일으키는 것은 아닙니다. (적어도 일부 버전) AIX, *(int *) 0 == 0 및 Solaris는이 AIX "기능"과 선택적 호환성을 가지고 있습니다.

원래 질문 : 내용을 풀고 난 후 직접 널로 포인터를 설정하는 것은 전체 요구 사항을 충족하고 완전히 디버깅되며 다시 수정되지 않으면 시간 낭비입니다. 반면에, 자유롭게 해방 된 포인터를 방어 적으로 무효화하는 것은 누군가가 무료 () 아래에 새로운 코드 블록을 추가 할 때, 원래 모듈의 디자인이 올바르지 않을 때, 그리고 그 경우에는 매우 유용 할 수 있습니다. -컴파일하지만 what-i-want 버그.

모든 시스템에서는 올바른 일을 가장 쉽게 만들 수있는 목표와 부정확 한 측정의 돌이킬 수없는 비용이 있습니다. C에서 우리는 매우 날카 롭고 강력한 도구 세트를 제공하여 숙련 된 노동자의 손에 많은 것들을 만들 수 있으며 부적절하게 다룰 때 모든 종류의 은유 적 부상을 입을 수 있습니다. 일부는 이해하거나 올바르게 사용하기가 어렵습니다. 그리고 자연스럽게 위험을 감수하는 사람들은 무료로 전화하기 전에 널 가치에 대한 포인터를 확인하는 것과 같은 비이성적 인 일을합니다.

측정 문제는 양호를 덜 좋은 것으로 나누려고 할 때마다 사례가 더 복잡할수록 모호한 측정을받을 가능성이 높다는 것입니다. 목표가 좋은 관행 만 유지한다면, 일부 모호한 사람들은 실제로 좋지 않은 것으로 던져집니다. 당신의 목표가 좋지 않은 것을 제거하는 것이라면, 모호성은 선을 유지할 수 있습니다. 두 가지 목표는 좋거나 분명하게 나쁘게 유지하는 것만으로도 정반대로 반대되는 것처럼 보이지만, 일반적으로 세 번째 그룹이 있는데, 다른 하나는 둘 중 일부가 있습니다.

품질 부서에서 사례를 만들기 전에 버그 데이터베이스를 살펴 보려면 유효하지 않은 포인터 값이 기록 해야하는 문제가 얼마나 자주 발생했는지 확인하십시오. 실질적인 차이를 만들려면 생산 코드에서 가장 일반적인 문제를 식별하고이를 방지하는 세 가지 방법을 제안하십시오.

두 가지 이유가 있습니다.

이중 무료로 충돌을 피하십시오

작성자가 작성했습니다 Ragez 안에 중복 질문.

C에서 가장 일반적인 버그는 이중 무료입니다. 기본적으로 당신은 그런 일을합니다

free(foobar);
/* lot of code */
free(foobar);

그리고 그것은 꽤 나쁘게 만들어졌습니다. OS는 이미 해방 된 메모리를 해방 시키려고 노력하고 일반적으로 Segfault를 해방 시키려고합니다. 따라서 모범 사례는 설정하는 것입니다 NULL, 따라서 테스트를 하고이 메모리를 자유롭게 해야하는지 확인할 수 있습니다.

if(foobar != NULL){
  free(foobar);
}

또한 주목해야합니다 free(NULL)아무것도하지 않으므로 if 문을 쓸 필요가 없습니다. 나는 실제로 OS 전문가는 아니지만 지금도 대부분의 OS는 더블 무료로 충돌 할 것입니다.

그것은 또한 쓰레기 수집 (Java, Dotnet)이있는 모든 언어 가이 문제가없고 개발자에게 메모리 관리를 전체적으로 떠나지 않아도 된 것을 자랑스럽게 생각한 주된 이유이기도합니다.

이미 해방 된 포인터를 사용하지 마십시오

작성자가 작성했습니다 마틴 대 로위 안에 또 다른 대답.

사용하지 않는 포인터를 NULL로 설정하는 것은 방어적인 스타일이며 매달려 포인터 버그로부터 보호합니다. 매달려있는 포인터가 해제 된 후에 액세스하면 무작위 메모리를 읽거나 덮어 쓸 수 있습니다. 널 포인터에 액세스하면 대부분의 시스템에서 즉시 충돌하여 오류가 무엇인지 즉시 알려줍니다.

로컬 변수의 경우, 해제 후 포인터에 더 이상 액세스하지 못한다는 것이 "명백한"경우 약간 무의미 할 수 있으므로이 스타일은 멤버 데이터 및 전역 변수에 더 적합합니다. 로컬 변수의 경우에도 메모리가 해제 된 후에 함수가 계속되면 좋은 접근 방식 일 수 있습니다.

스타일을 완성하려면 Pointers가 실제 포인터 값을 할당하기 전에 NULL로 초기화해야합니다.

품질 보증 팀이 있으므로 QA에 대한 사소한 포인트를 추가하겠습니다. C를위한 일부 자동화 된 QA 도구 ptr". 예를 들어 Gimpel Software의 PC-Lint/Flexelint와 같은tst.c 8 Warning 438: Last value assigned to variable 'nPtr' (defined at line 5) not used

메시지를 선택적으로 억제하는 방법이 있으므로 팀이 그렇게 결정한 경우 여전히 두 QA 요구 사항을 모두 만족시킬 수 있습니다.

포인터 변수를 없는 와 같은,

int *ptr = NULL;

의 말을하자, ptr 가리키고 있습니다 0x1000 메모리 주소. 사용 후 free(ptr), 다시 선언하여 포인터 변수를 무효화하는 것이 항상 권장됩니다. 없는. 예 :

free(ptr);
ptr = NULL;

다시 고추되지 않은 경우 없는, 포인터 변수는 여전히 동일한 주소를 계속 지적합니다 (0x1000),이 포인터 변수는 a라고합니다 매달려 포인터. 다른 포인터 변수를 정의하면 ) 새 포인터에 주소를 동적으로 할당하면 동일한 주소를 취할 가능성이 있습니다 (0x1000) 새로운 포인터 변수에 의해. 경우에 동일한 포인터를 사용하는 경우 (ptr) 및 동일한 포인터로 가리키는 주소에서 값을 업데이트합니다 (ptr), 그러면 프로그램은 그 장소에 가치를 쓸 것입니다. 가리키고 있습니다 (이후 그리고 같은 주소를 가리키고 있습니다 (0x1000)).

예를 들어

*ptr = 20; //Points to 0x1000
free(ptr);
int *q = (int *)malloc(sizeof(int) * 2); //Points to 0x1000
*ptr = 30; //Since ptr and q are pointing to the same address, so the value of the address to which q is pointing would also change.

짧은 긴 이야기:당신이 원하지 않는 실수로(실수로)에 액세스 주소를 해제됩니다.기 때문에,경우 무료 주소,당신은 당신을 허용하는 주소에 힙 할당될 수 있는 다른 응용 프로그램.

그러나,설정하지 않는 경우 포인터 NULL,과 실수에 의해 시도하는 데 참조로 포인터 또는 변경의 가치는 주소;당신은 여전히 그것을 할 수 있습니다.하지만 무언가가는 당신은 논리적으로 다하겠습니다.

왜 난 아직도에 액세스하는 메모리 위치는 나는 자유를 누리고 싶은가?기:당신이 기억하지만,포인터 변수도에 대한 정보를 힙 메모리 주소입니다.그래서,전략,주시기 바랍 NULL 로 설정합니다.

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