NULL 포인터를 삭제해도 안전합니까?


299

NULL 포인터를 삭제해도 안전합니까?

그리고 좋은 코딩 스타일입니까?


21
한 번의 호출없이 C ++ 프로그램을 작성하는 것이 좋습니다 delete. 대신 RAII 를 사용하십시오 . 즉 사용된다 std::vector<T> v(100);대신 T* p = new T[100];, 스마트 같은 포인터 사용 unique_ptr<T>shared_ptr<T>등 삭제의 돌봐 대신 원시 포인터
fredoverflow

8
덕분에 make_shared(C ++ 11)와 make_unique(C ++ 14) 프로그램이 포함되어 있어야합니다 제로newdelete
sp2danny

2
atomic / T <>가 허용되지 않고 atomic <shared_ptr <T >>에 오버 헤드가있어 어떤 경우에는 받아 들일 수없는 새 / 삭제가 필요한 경우가 여전히있을 수 있습니다.
atb

2
RAII를 사용하여 자원 관리가있는 클래스를 선언하려면 new를 호출하고 바로 삭제해야합니까? 또는 이것을 숨길 수있는 템플리트 클래스가 있다고 말하고 있습니다.
VinGarcia

2
@VinGarcia는 점은 가장이다 사용자 / 클라이언트 코드를 작성할 필요가해서는 안됩니다 : (비 라이브러리입니다) newdelete. 표준 구성 요소가 작업을 수행 할 수없는 리소스를 관리하도록 설계된 클래스는 물론 필요한 작업을 수행 할 수 있지만 요점은 최종 사용자 코드가 아니라 관리하는 메모리로 추악한 작업을 수행 한다는 입니다. 그래서, 자신의 라이브러리 / 헬퍼 클래스가 할 수 있도록 new/ delete, 그 대신 그 클래스를 사용합니다.
underscore_d

답변:


265

delete어쨌든 검사를 수행하므로 측면에서 검사하면 오버 헤드가 추가되고 추악하게 보입니다. 아주 좋습니다 후에 NULL 포인터를 설정하는 것입니다 delete(더블 삭제 및 기타 유사한 메모리 손상 문제를 방지하는 데 도움).

delete기본적으로 매개 변수를 NULL로 설정하는 것이 좋을 것 입니다.

#define my_delete(x) {delete x; x = NULL;}

(R 및 L 값에 대해서는 알고 있지만 좋지 않습니까?)


72
삭제시 하나를 NULL로 설정하더라도 동일한 객체를 가리키는 다른 여러 포인터가 여전히있을 수 있습니다.
sth

13
내 코드에서 대부분의 경우 포인터가 삭제되면 포인터가 범위를 벗어납니다. 단순히 NULL로 설정하는 것보다 훨씬 안전합니다.
jalf

142
매우 신 연습이되어 있지 삭제 후 NULL 포인터를 설정. 포인터를 삭제 한 후 NULL로 포인터를 설정하면 메모리 할당 오류가 발생합니다. 이는 매우 나쁜 문제입니다. 올바른 프로그램은 포인터를 두 번 삭제하지 않으며 포인터를 두 번 삭제하는 프로그램 충돌합니다.
Damon

15
@ 앨리스 : 표준이 그 점에서 말하는 것과 관련이 없습니다. 이 표준은 30 년 전의 불합리한 이유로 유효하지 않은 널 포인터를 삭제하도록 정의 했으므로 합법적 일 가능성이 높습니다 (대부분 C 레거시). 그러나 비트 패턴을 변경 한 후에도 동일한 포인터를 두 번 삭제하면 여전히 심각한 프로그램 오류입니다. 표준의 말이 아니라 프로그램 논리와 소유권에 의한 것입니다. null 포인터를 삭제하는 것과 같이 null 포인터 는 object에 해당 하지 않으므로 아무것도 삭제할 수 없습니다. 프로그램은 개체가 유효한지, 누가 소유하고 있는지, 언제 삭제할 수 있는지 정확하게 알고 있어야합니다 .
Damon

27
@Damon 그러나 드라코 니안 소유권 규칙에 대한 이러한 폐지에도 불구하고 잠금 해제 구조는 잠금 기반 구조보다 훨씬 강력합니다. 그리고 그렇습니다. 동료들은 이러한 구조가 제공하는 강화 된 실행 프로필과 그들이 유지하는 엄격한 스레드 안전성으로 인해 저를 사랑합니다. 코드에 대해 쉽게 추론 할 수 있습니다 (유지 보수에 좋습니다). 그러나 이것과 귀하의 암시 적 개인 공격은 정확성, 타당성 또는 소유권의 정의와 관련이 없습니다. 당신이 제안하는 것은 좋은 경험 법칙이지만 보편적 인 법칙이 아니며 표준에 포함되어 있지도 않습니다.
Alice

77

C ++ 0x 표준 초안에서.

$ 5.3.5 / 2- "[...] 다른 방법으로 delete 피연산자의 값은 널 포인터 값일 수 있습니다. [... '"

물론 아무도 NULL 값을 가진 포인터를 '삭제'하지는 않지만 안전합니다. 이상적으로는 NULL 포인터를 삭제하는 코드가 없어야합니다. 그러나 포인터 삭제 (예 : 컨테이너)가 루프에서 발생할 때 유용합니다. NULL 포인터 값을 삭제하는 것이 안전하기 때문에 NULL 피연산자를 삭제하도록 명시 적으로 검사하지 않고도 삭제 논리를 실제로 작성할 수 있습니다.

한편, C 표준 $ 7.20.3.2는 NULL 포인터에서 '무료'는 아무런 조치도 취하지 않는다고 말합니다.

free 함수는 ptr이 가리키는 공간을 할당 해제, 즉 추가 할당에 사용 가능하게합니다. ptr이 널 포인터이면 조치가 발생하지 않습니다.


2
최적화되지 않은 코드에서 의도적으로 비효율적이지 않은 경우 인용에 대해이 답변을 정말로 원합니다. 허용되는 답변에서 알 수 있듯이 null 포인터를 삭제하면 아무런 문제가 없습니다. 따라서 포인터를 삭제하기 전에 널이 아닌지 확인하는 것은 완전히 불필요한 것입니다.
codetaku

47

예, 안전합니다.

널 포인터를 삭제해도 아무런 해가 없습니다. 할당되지 않은 포인터가 0으로 초기화 된 다음 단순히 삭제되면 함수의 꼬리에서 테스트 횟수가 줄어 듭니다.


이전 문장이 혼동을 일으켰으므로, 설명 할 내용에 대한 예는 예외 안전하지는 않습니다.

void somefunc(void)
{
    SomeType *pst = 0;
    AnotherType *pat = 0;

    
    pst = new SomeType;
    
    if (…)
    {
        pat = new AnotherType[10];
        
    }
    if (…)
    {
        code using pat sometimes
    }

    delete[] pat;
    delete pst;
}

샘플 코드로 선택할 수있는 모든 종류의 니트가 있지만 개념은 분명합니다. 포인터 변수는 0으로 초기화되므로 delete함수 끝의 연산이 소스 코드에서 널이 아닌지 여부를 테스트 할 필요가 없습니다. 라이브러리 코드는 어쨌든 해당 검사를 수행합니다.


나는 그것을 이해하기 위해 몇 번 읽어야했다. 메소드의 맨 위 또는 테일이 아닌 그 사이에 반드시 0으로 초기화하는 것을 의미해야합니까? 그렇지 않으면 제로화와 삭제를 모두 제거합니다.
Lorne의 후작

1
@EJP : 함수의 전체적으로 설명 할 수없는 개요는 다음과 같습니다 void func(void) { X *x1 = 0; Y *y1 = 0; … x1 = new[10] X; … y1 = new[10] Y; … delete[] y1; delete[] x1; }. 블록 구조 나 점프를 표시하지 않았지만 delete[]시작시 초기화로 인해 마지막 작업이 안전합니다. 무언가 x1가 할당 된 후 와 할당되기 전에 끝났 y1으며 초기화가없는 y1경우 정의되지 않은 동작이있을 수 있습니다. 코드가 삭제 전에 null (of x1y1)을 테스트 할 수 는 있지만 수행 할 필요는 없습니다. 그래서.
Jonathan Leffler

22

널 포인터를 삭제해도 효과가 없습니다. 필요하지 않기 때문에 반드시 코딩 스타일이 좋지는 않지만 나쁘지는 않습니다.

좋은 코딩 방법을 찾고 있다면 대신 스마트 포인터 사용을 고려하면 전혀 필요하지 않습니다 delete.


20
사람들이 NULL 포인터를 삭제하려는 시간은 NULL이 포함되어 있는지 확실하지 않을 때입니다. NULL을 알고 있다면 삭제를 고려하지 않으므로 ;-)를 묻지 않습니다.
Tony Delroy

@Tony : 내 요점은 효과가 없다는 것 뿐이며 때로는 NULL을 포함하는 포인터를 삭제하는 그러한 코드가 반드시 나쁜 것은 아닙니다.
Brian R. Bondy

3
IMO 리던던트 검사는 성능, 가독성 및 유지 관리 성이 확실하지 않습니다.
paulm

@paulm OP는 확실히 Seg Fault / UB 종류의 나쁜 종류에 대해 이야기하지 않습니다.
Winter

8

ruslik의 답변 을 보완하기 위해 C ++ 14에서는 다음 구성을 사용할 수 있습니다.

delete std::exchange(heapObject, nullptr);

3

삭제 연산자에 과부하가 걸리지 않는 한 안전합니다. 삭제 연산자를 오버로드하고 null 조건을 처리하지 않으면 전혀 안전하지 않습니다.


답변에 대한 설명을 추가해 주시겠습니까?
Marcin Nabiałek

-2

NULL (즉, 배열 구문)을 삭제하는 것이 안전 하지 않다는 것을 경험했습니다 (VS2010). 이것이 C ++ 표준을 따르는 지 확실하지 않습니다.

그것은 이다 삭제 NULL (스칼라 구문)에 안전합니다.


6
이것은 불법이며 믿지 않습니다.
Konrad Rudolph

5
널 포인터를 삭제할 수 있어야합니다. 따라서 그것이 당신을 어길 경우 코드에 버그가있을 수 있습니다.
신비주의

3
§5.3.2 두 번째 대안 (배열 삭제)에서, 삭제 피연산자의 값은 널 (null) 포인터 값이거나 이전 배열의 새로운 표현식으로 인한 포인터 값일 수 있습니다 .
sp2danny

1
@Opux 답변에서 주장 된 VS2010의 동작. 다른 의견에서 설명했듯이 안전합니다 delete[] NULL.
Konrad Rudolph

1
@Opux 그래서 나는“그것이 틀렸다”보다는“믿지 않는다”라고 썼습니다. 그러나 나는 여전히 그렇지 않으며 표준을 상당히 어리 석고 어리석은 위반 일 것입니다. VC ++는 일반적으로 표준의 제한 사항을 따르는 데 능숙하며,이를 위반하는 장소는 역사적으로 의미가 있습니다.
Konrad Rudolph
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.