삭제로 포인터를 NULL로 설정하지 않는 이유는 무엇입니까?


127

삭제 후 포인터를 자동으로 NULL로 설정하는 것이 왜 표준의 일부가 아닌지 항상 궁금했습니다 . 이것이 처리되면 유효하지 않은 포인터로 인한 많은 충돌이 발생하지 않습니다. 그러나 표준이 이것을 제한 한 몇 가지 이유를 생각할 수 있다고 말했습니다.

  1. 공연:

    추가 명령을 delete수행 하면 성능 이 저하 될 수 있습니다.

  2. const포인터 때문일 수 있습니다 .

    그런 다음 표준은이 특별한 경우를 위해 무언가를 할 수 있다고 생각합니다.

아무도 이것을 허용하지 않는 정확한 이유를 알고 있습니까?

답변:


150

Stroustrup 자신이 대답합니다. 발췌 :

C ++은 delete 구현이 lvalue 피연산자를 제로화 할 수 있도록 명시 적으로 허용하며 구현에서 그렇게하기를 희망했지만 그 아이디어는 구현 자에게 인기가없는 것으로 보입니다.

그러나 그가 제기하는 주요 문제는 delete의 인수가 lvalue 일 필요는 없다는 것입니다.


나는 이것이 더 많은 설명을 사용할 수 있다고 생각합니다. 나는 그가 무슨 말을하는지 잘 모르겠다 ... 나는 이것을 얻을 때까지 이것을 연구하는 데 몇 시간을 투자 할 수있을 때 나중에 다시 돌아와야한다고 생각한다. 또는 더 빨리 이해하도록 돕기 위해 답을 설명 할 수 있습니다.
Gabriel Staples

63

먼저 null로 설정하려면 메모리 저장 변수가 필요합니다. 일반적으로 변수에 포인터가 있지만 때로는 계산 된 주소에서 객체 를 삭제 하려고 할 수도 있습니다 . "nullifying"삭제로는 불가능합니다.

그런 다음 성능이 제공됩니다. 삭제 가 완료된 직후 포인터가 범위를 벗어나는 방식으로 코드를 작성했을 수 있습니다 . null로 채우는 것은 시간 낭비입니다. 그리고 C ++는 "필요하지 않습니까? 그렇다면 돈을 지불 할 필요가 없습니다"라는 이념이있는 언어입니다.

안전이 필요한 경우 서비스에 광범위한 스마트 포인터가 있거나 더 좋고 똑똑한 자신만의 글을 쓸 수 있습니다.


4
좋은 점 wrt는 주소가 자주 보이지 않더라도 주소를 계산했습니다.
snemarch

때로는 계산 된 주소에서 객체를 삭제하고 싶을 때 새로운 배치에 대해 이야기하고 있습니까? ???
Destructor

@PravasiMeet 아니요, 예를 들어delete (ptr + i)
sharptooth

39

해당 메모리를 가리키는 포인터가 여러 개있을 수 있습니다. 삭제에 지정한 포인터가 null로 설정되었지만 다른 모든 포인터가 그렇지 않은 경우 잘못된 보안 감각을 만듭니다. 포인터는 주소, 숫자에 지나지 않습니다. 역 참조 작업이있는 int 일 수도 있습니다. 내 요점은 모든 단일 포인터를 스캔하여 방금 삭제 한 동일한 메모리를 참조하는 포인터를 찾아서 null을 제거해야한다는 것입니다. 해당 주소에 대한 모든 포인터를 스캔하고 언어가 설계되지 않았기 때문에 null을 계산하는 것은 계산 상 강렬합니다. (일부 다른 언어는 비슷한 방식으로 다른 목표를 달성하기 위해 참조를 구성합니다.)


19

포인터는 둘 이상의 변수에 저장 될 수 있으며, 이들 중 하나를 NULL로 설정하면 다른 변수에는 여전히 유효하지 않은 포인터가 남습니다. 그래서 당신은 실제로 많은 것을 얻지 못하고, 잘못된 보안 감각을 만들 가능성이 큽니다.

그 외에도 원하는 것을 수행하는 고유 한 함수를 만들 수 있습니다.

template<typename T>
void deleten(T *&ptr) {
  delete ptr;
  ptr = NULL;
}

12

실제로 필요가 없기 때문에 포인터가 아닌 포인터를 포인터로 가져 가려면 삭제가 필요하기 때문입니다.


사실이지만 동일한 오버 헤드를 초래할 것입니다
snemarch

7

delete소멸자에서 주로 사용되며,이 경우 멤버를 NULL로 설정하는 것은 의미가 없습니다. 몇 줄 후, 닫는 시점 }에 멤버가 더 이상 존재하지 않습니다. 할당 연산자에서 삭제는 일반적으로 할당 뒤에 이어집니다.

또한 다음 코드를 불법으로 만듭니다.

T* const foo = new T;
delete foo;

6

여기 또 다른 이유가 있습니다. delete가 인수를 NULL로 설정한다고 가정합니다.

int *foo = new int;
int *bar = foo;
delete foo;

막대가 NULL로 설정되어야합니까? 이것을 일반화 할 수 있습니까?


5

포인터 배열이 있고 두 번째 조치가 빈 배열을 삭제하는 것이라면 메모리가 해제 될 때 각 값을 널로 설정하는 포인트가 없습니다. 널이 되길 원한다면 .. :)


4

C ++를 사용하면 자신 만의 연산자를 새로 정의하고 삭제할 수 있으므로 예를 들어 자신의 풀 할당자를 사용할 수 있습니다. 이렇게하면 엄격하게 주소가 아닌 풀 배열의 인덱스라고하는 항목으로 new를 사용하고 삭제할 수 있습니다. 이와 관련하여 NULL (0) 값은 올바른 의미를 가질 수 있습니다 (풀의 첫 번째 항목 참조).
따라서 delete NULL을 인수에 자동으로 설정한다고해서 항상 의미가있는 것은 아닙니다. 값을 유효하지 않은 값으로 설정하십시오. 유효하지 않은 값이 항상 NULL 인 것은 아닙니다.


4

C ++의 철학은 "사용하는 경우에만 지불"입니다. 나는 그것이 당신의 질문에 대답 할 수 있다고 생각합니다.

또한 때로는 삭제 된 메모리를 복구하는 자체 힙을 가질 수도 있습니다. 또는 때로는 변수가 소유하지 않은 포인터가 있습니다. 또는 몇 가지 변수에 저장된 포인터-그중 하나만 가능합니다.
보시다시피 많은 문제와 가능한 문제가 있습니다.


3

포인터를 자동으로 NULL로 설정하면 잘못된 포인터 사용과 관련된 대부분의 문제가 해결되지 않습니다. 피할 수있는 유일한 충돌은 두 번 삭제하려고하는 것입니다. 그러한 포인터에서 멤버 함수를 호출하면 어떻게됩니까? 멤버 변수에 액세스한다고 가정하면 여전히 충돌합니다. C ++은 NULL 포인터에서 함수를 호출하는 것을 제한하지 않으며 성능 관점에서 수행해서는 안됩니다.


-1

사람들이이 질문에 이상한 답을주는 것을 봅니다.

ptr = NULL; 그러한 간단한 진술이 어떻게 성능 지연을 일으킬 수 있습니까?

또 다른 대답은 동일한 메모리 위치를 가리키는 여러 개의 포인터를 가질 수 있다는 것입니다. 분명히 우리는 할 수 있습니다. 이 경우 하나의 포인터에서 삭제 작업을 수행하면 해당 포인터 만 NULL이되고 (삭제가 포인터를 NULL로 만든 경우) 다른 포인터는 NULL이 아니며 사용 가능한 메모리 위치를 가리 킵니다.

이에 대한 해결책은 사용자가 동일한 위치를 가리키는 모든 포인터를 삭제해야한다는 것입니다. 내부적으로 메모리가 여유 공간보다 이미 비어 있는지 확인해야합니다. 포인터를 NULL로만 만드십시오.

Stroustrup은 이러한 방식으로 작동하도록 삭제를 설계했을 수 있습니다. 그는 프로그래머들이 이것을 처리 할 것이라고 생각했다. 그래서 그는 무시했다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.