문제

나는 종종 레거시 코드를 확인하는 것을 본다 NULL 포인터를 삭제하기 전에

if (NULL != pSomeObject) 
{
    delete pSomeObject;
    pSomeObject = NULL;
}

확인해야 할 이유가 있습니까? NULL 삭제하기 전에 포인터? 포인터를 설정 한 이유는 무엇입니까? NULL 나중에?

도움이 되었습니까?

해결책

널 포인터를 삭제하는 것은 완벽하게 "안전합니다. 효과적으로 NO-OP에 해당합니다.

삭제하기 전에 NULL을 확인하려는 이유는 NULL 포인터를 삭제하려고하면 프로그램의 버그가 표시 될 수 있기 때문입니다.

다른 팁

C ++ 표준은 삭제-표현 (§8.5.2.5/2). 그러나 그것은입니다 지정되지 않았습니다 이것이 거래 함수를 호출할지 여부 (operator delete 또는 operator delete[]; §8.5.2.5/7, 참고).

기본 거래 함수 (즉, 표준 라이브러리에서 제공)가 널 포인터로 호출되면 호출은 효과가 없습니다 (§6.6.4.4.2/3).

그러나 표준 라이브러리에서 거래 기능이 제공되지 않으면 어떻게되는지 지정되지 않습니다. 즉, 과부하 할 때 발생하는 일 operator delete (또는 operator delete[]).

유능한 프로그래머는 그에 따라 널 포인터를 처리합니다 내부에 OP의 코드에 표시된대로 호출 전이 아닌 거래 기능은 포인터를 설정합니다. nullptr/NULL 삭제 후에는 매우 제한된 목적 만 사용합니다. 어떤 사람들은 방어 프로그래밍: 버그의 경우 프로그램 동작이 약간 더 예측 가능합니다. 삭제 후 포인터에 액세스하면 임의의 메모리 위치에 대한 액세스가 아닌 널 포인터 액세스가 발생합니다. 두 작업이 정의되지 않은 동작이지만, 널 포인터 액세스의 동작은 실제로 훨씬 더 예측 가능합니다 (대부분 메모리 손상보다는 직접 충돌이 발생합니다). 메모리 손상은 특히 디버깅하기가 어렵 기 때문에 삭제 된 포인터 보조 장치를 재설정합니다.

- 물론 이것은 원인이 아니라 증상을 치료하는 것입니다 (즉, 버그). 재설정 포인터를 코드 냄새로 취급해야합니다. 깨끗하고 현대적인 C ++ 코드는 메모리 소유권을 명확하고 정적으로 점검하여 (스마트 포인터 또는 동등한 메커니즘을 사용하여)이 상황을 피할 수 있습니다.

보너스 : 과부하에 대한 설명 operator delete:

operator delete (이름에도 불구하고) 다른 함수와 같이 과부하 될 수있는 함수입니다. 이 기능은 모든 호출에 대해 내부적으로 호출됩니다 operator delete 일치하는 인수와 함께. 마찬가지입니다 operator new.

과부하 operator new (그리고 또한 operator delete) 메모리가 할당되는 방식을 정확하게 제어하려는 경우 어떤 상황에서는 의미가 있습니다. 이렇게하는 것은 그리 어렵지 않지만 올바른 행동을 보장하기 위해 몇 가지 예방 조치를 취해야합니다. Scott Meyers는 이것을 자세히 설명합니다 효과적인 C ++.

지금은 글로벌 버전을 과부하하고 싶다고 가정 해 봅시다. operator new 디버깅을 위해. 이렇게하기 전에 다음 코드에서 발생하는 일에 대한 짧은 통지는 다음과 같습니다.

klass* pobj = new klass;
// … use pobj.
delete pobj;

실제로 여기서 무슨 일이 일어나나요? 위의 내용은 대략 다음 코드로 번역 될 수 있습니다.

// 1st step: allocate memory
klass* pobj = static_cast<klass*>(operator new(sizeof(klass)));
// 2nd step: construct object in that memory, using placement new:
new (pobj) klass();

// … use pobj.

// 3rd step: call destructor on pobj:
pobj->~klass();
// 4th step: free memory
operator delete(pobj);

2 단계 우리가 전화하십시오 new 약간 이상한 구문. 이것은 소위 호출입니다 놓기 new 주소를 취하고 해당 주소에 객체를 구성합니다. 이 연산자도 과부하 할 수 있습니다. 이 경우 클래스의 생성자를 호출하는 역할을합니다. klass.

이제 더 이상 고민하지 않고 오버로드 된 버전의 연산자에 대한 코드가 있습니다.

void* operator new(size_t size) {
    // See Effective C++, Item 8 for an explanation.
    if (size == 0)
        size = 1;

    cerr << "Allocating " << size << " bytes of memory:";

    while (true) {
        void* ret = custom_malloc(size);

        if (ret != 0) {
            cerr << " @ " << ret << endl;
            return ret;
        }

        // Retrieve and call new handler, if available.
        new_handler handler = set_new_handler(0);
        set_new_handler(handler);

        if (handler == 0)
            throw bad_alloc();
        else
            (*handler)();
    }
}

void operator delete(void* p) {
    cerr << "Freeing pointer @ " << p << "." << endl;
    custom_free(p);
}

이 코드는 사용자 정의 구현 만 사용합니다 malloc/free 대부분의 구현과 마찬가지로 내부적으로. 또한 디버깅 출력을 만듭니다. 다음 코드를 고려하십시오.

int main() {
    int* pi = new int(42);
    cout << *pi << endl;
    delete pi;
}

다음 출력을 산출했습니다.

Allocating 4 bytes of memory: @ 0x100160
42
Freeing pointer @ 0x100160.

이제이 코드는 표준 구현과 근본적으로 다른 것을 수행합니다. operator delete: 널 포인터를 테스트하지 않았습니다! 컴파일러는 이것을 점검하지 않으므로 위의 코드가 컴파일되지만 런 타임에 널 포인터를 삭제하려고 할 때 불쾌한 오류가 발생할 수 있습니다.

그러나 앞서 말했듯이,이 행동은 실제로 예상치 못한 일이며 도서관 작가 ~해야 한다 널 포인터를 확인하십시오 operator delete. 이 버전은 훨씬 개선되었습니다.

void operator delete(void* p) {
    if (p == 0) return;
    cerr << "Freeing pointer @ " << p << "." << endl;
    free(p);
}

결론적으로, 비록 조잡한 구현 operator delete 클라이언트 코드에서 명백한 널 확인이 필요할 수 있습니다. 이것은 비표준 동작이며 레거시 지원에만 견딜 수 있어야합니다 (전혀).

내부적으로 NULL 수표를 삭제합니다. 시험은 중복됩니다

NULL을 삭제하는 것은 NO-OP입니다. Delete에 전화하기 전에 NULL을 확인할 이유가 없습니다.

포인터가 Null이라는 추가 정보를 제공하는 경우 다른 이유로 NULL을 확인하고 싶을 수도 있습니다.

C ++ 03 5.3.5/2에 따르면 널 포인터를 삭제하는 것이 안전합니다. 다음은 표준에서 인용됩니다.

두 대안에서, 삭제의 피연산자 값이 널 포인터 인 경우, 작동은 효과가 없다.

psomeobject가 null이면 Delete는 아무것도하지 않습니다. 아니요, Null을 확인할 필요가 없습니다.

우리는 일부 너클 헤드가 포인터를 사용하려고 시도 할 수 있다면 삭제 후 널을 포인터에 할당하는 것이 좋습니다. 널 포인터를 사용하면 누가 알고있는 사람에 대한 포인터를 사용하는 것보다 약간 낫습니다 (널 포인터가 충돌을 일으킬 것입니다.

삭제 전에 NULL을 확인할 이유가 없습니다. 코드 점검 어딘가에 널 점검을 수행하여 일부 객체가 이미 할당되었는지 여부에 관계없이 삭제 후 NULL 할당이 필요할 수 있습니다. 예를 들어 주문시 주문에 따라 할당 된 일종의 캐시 데이터가 있습니다. 캐시-객체를 지울 때마다 포인터에 null을 할당하므로 객체에 할당하는 코드는 할당을 수행해야한다는 것을 알고 있습니다.

이전 개발자는 일부 밀리 초 절약을 위해 "중복"을 코딩했다고 생각합니다. 삭제 될 때 포인터를 Null로 설정하는 것이 좋습니다. 따라서 객체를 삭제 한 후 바로 다음과 같은 줄을 사용할 수 있습니다.

if(pSomeObject1!=NULL) pSomeObject1=NULL;

그러나 삭제는 어쨌든 그 정확한 비교를 수행합니다 (널이면 아무것도하지 않습니다). 왜 이렇게하면 두 번? 현재 값에 관계없이 삭제를 호출 한 후 psomeObject를 널에 할당 할 수 있습니다. 그러나 이미 해당 값이있는 경우 약간 중복됩니다.

따라서 내 베팅은 잠재적으로 불필요한 테스트 및 할당 비용을 발생시키지 않고 PsomeObject1이 삭제 된 후에는 항상 null이 될 수 있도록 시도한 라인의 저자입니다.

그것은 당신이하는 일에 달려 있습니다. 일부 오래된 구현 free, 예를 들어, 그들이 통과하면 행복하지 않을 것입니다. NULL 바늘. 일부 라이브러리에는 여전히이 문제가 있습니다. 예를 들어, XFree XLIB 라이브러리에서 다음과 같이 말합니다.

설명

Xfree 함수는 지정된 데이터를 해방시키는 일반적인 목적 XLIB 루틴입니다. 대체 함수가 개체에 대해 명시 적으로 지정되지 않는 한 xlib에 의해 할당 된 객체를 제거하는 데 사용해야합니다. 널 포인터는이 기능으로 전달할 수 없습니다.

그러니 자유를 고려하십시오 NULL 버그로 포인터를하면 안전합니다.

내 관찰에 관해서는, Delete를 사용하여 널 포인터를 삭제하는 것은 UNIX 기반 기계 IKE Parisc 및 Itanium에서 안전합니다. 그러나 프로세스가 충돌하므로 Linux 시스템에 대해서는 안전하지 않습니다.

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