2010-07-19 3 views
20

메모리 동적 할당을 조금했는데 점수가 없습니다. new 문으로 일부 메모리를 할당 할 때 포인터가 가리키는 메모리를 파괴 할 수 있어야합니다. delete을 사용하십시오.왜 아무것도 파괴하지 않습니까?

하지만 시도 할 때이 delete 명령이 포인터가 가리키고있는 공간이 비어 있지 않기 때문에 작동하지 않는 것 같습니다.

을 예로 들어이 코드 정말 기본적인 부분을 보자 :

#include <iostream> 

using namespace std; 

int main() 
{ 
    //I create a pointer-to-integer pTest, make it point to some new space, 
    // and fulfill this free space with a number; 
    int* pTest; 
    pTest = new int; 
    *(pTest) = 3; 
    cout << *(pTest) << endl; 

    // things are working well so far. Let's destroy this 
    // dynamically allocated space! 
    delete pTest; 

    //OK, now I guess the data pTest pointed to has been destroyed 
    cout << *(pTest) << endl; // Oh... Well, I was mistaking. 

    return 0; 
} 

어떤 단서?

+13

예, 멍청한 quieston지만 사소한 것은 아닙니다. – sharptooth

답변

54

그것은이 정의되지 않은 어떤 행동을 배울 수있는 시간이다. :)

C++에서는 불법/무의미한/나쁜/등을 할 때. 표준은 종종 "정의되지 않은 행동으로 이어집니다"라고 말합니다. 이것은 그 시점부터 프로그램의 상태가 완전히 보증되지 않으며 어떤 일이 발생할 수 있음을 의미합니다.

마지막으로 *(pTest) 할 시점에서 정의되지 않은 동작이 발생합니다. pTest이 유효한 개체를 가리 키지 않고 그러한 포인터의 역 참조가 정의되지 않았기 때문입니다. 따라서보고있는 것은 완전히 허용됩니다. 정의되지 않은 출력입니다.

"이 할당이 끝났습니다."라고 말하면됩니다. 일단 당신이 그렇게 말하면, 당신은 그 기억에 대해 더 이상 검사하거나 신경을 써서는 안됩니다. 그것은 개념적으로 뭔가를 할당 해제 한 다음 사용하려고 시도하지도 않습니다. 너는 끝났다고 했어!

출력이 다소 예측 가능합니다. OS에서 "okay, memory for thanks"라고 간단히 말하면됩니다. 실제로 메모리를 "재설정"하거나 특별한 작업을 수행 할 이유가 없습니다. 그것은 실제로 아무도 자신의 프로그램을 포함하여 아무도 그것을 사용하지 않을 때 시간 낭비 일 것입니다.

그러나이 출력은 완전히 정의되지 않았습니다. 존재하지 않는 객체를 사용하지 마십시오. 아마도 더 나은 테스트가 있었을 것입니다 :

#include <iostream> 

struct foo 
{ 
    ~foo() 
    { 
     std::cout << "foo is gone :(" << std::endl; 
    } 
}; 

int main(void) 
{ 
    foo* f = new foo(); 
    delete f; // you'll see that the object is destroyed. 
} 

아마도 메모리 자체에서 어떤 일이 일어나는지 보려고했을 것입니다. 기억을 없애고 그것을 사용하려고 시도하는 것은 의미가 없다는 것을 기억하십시오. 따라서 대답은 : 누가 압니다. C++이 신경 쓰지 않는 특정 플랫폼에 달려 있습니다.

+27

정의되지 않은 동작에 대한 추악한 점은 대부분의 시간이 좋은 것처럼 보입니다. – peterchen

4

delete 연산자는 객체의 소멸자를 호출하고 이전에 객체에 할당 된 메모리를 할당 해제합니다. 삭제 된 개체를 가리키는 포인터 변수에는 영향을주지 않습니다.

따라서 파괴 된 개체를 가리키는 포인터를 역 참조하면 문제가 발생할 수 있습니다.

10

삭제를 호출하면 메모리 영역이 비어있는 것으로 표시됩니다. 이전 값을 다시 설정할 필요가 없습니다.

은 삭제 호출 한 후, 0으로 포인터를 설정하는 것이 좋습니다 :

delete pTest; 
pTest = 0; 
+2

대신'delete'를 호출 한 후에 변수 _at all_을 사용하지 말 것을 권합니다. (... 물론 다른 곳으로 재 할당하지 않는 한). – stakx

+9

더 나은 해결책은 변수가 삭제 직후에 범위를 벗어나서 다시 사용할 수 없도록하는 것입니다. –

0

매핑 된 메모리를 참조 할 수 있습니다. 또는 프로그램이 얼마나 오랫동안 실행되었는지, 메모리 할당에 대한 세부 사항 및 라이브러리가 나중에 OS로 메모리를 반환하는지에 따라 맵핑되지 않은 메모리 일 수도 있습니다.

delete이 실제로 삭제되는 메모리를 모두 지우면 프로그램이 실제로는 조만간 덮어 쓰게 될 메모리를 제거하는 데 많은 시간을 낭비하게되므로 상당히 오래 실행됩니다. 디버깅에는 좋을 수도 있지만, 프로덕션 환경에서는 메모리 내용을 실제로 제거하라는 요구가별로 없습니다. 물론 암호화 키는 좋은 예외입니다. delete 또는 free을 호출하기 전에 암호화 키를 사용하는 것이 좋습니다.

1

데이터를 파괴하는 것은 무엇을 의미합니까? 나는 그것이 제로가 될 수 있다고 생각하지만, 왜 귀찮게합니까? 환경에서 가져올 때 더러 웠다고 가정하기 때문에 반환하기 전에 왜 청소해야합니까? 우리는 그것을 읽을 권리를 포기하기 때문에 그 안에 무엇이 있는지 관심이 없습니다. 그리고 포인터 자체 제로화하지 않는 이유 삭제에 관해서 : 할당이 해제 된 메모리를 가리키는 포인터 역 참조

http://www2.research.att.com/~bs/bs_faq2.html#delete-zero

2

을 정의되지 않은 동작입니다.

new에 의해 제공되는 메모리는 일반적으로 할당자가 관리하는 할당 된 메모리의 더 큰 부분입니다. delete에 전화하면 관련된 소멸자를 호출하고 메모리를 "재사용 대기 중"이라고 표시하는 빈 공간으로 표시합니다. 따라서 해당 메모리를 살펴보면 delete에 대한 호출 이전에 있던 것과 동일한 데이터 또는 new 호출 후에 해당 메모리 덩어리가 다시 할당 된 경우 다른 데이터를 찾을 수 있습니다.

new 할당자는 OS 가상 메모리 기능에 대한 씬 래퍼로 작동하지 않으므로 페이지에 관련된 모든 할당 된 블록의 할당이 해제되면 전체 페이지가 해제되고 액세스 시도가 발생합니다 주소 위반이 발생합니다.

TL, DR 버전 : 할당 취소 된 메모리를 가리키는 포인터를 보류하지 마십시오. 가끔씩 작동 할 수도 있고 때때로 가비지를 다시 줄 수도 있습니다. 가끔 액세스 위반을 유발합니다.

이런 종류의 실수를하는 경우 즉시 알아 두는 좋은 방법은 포인터가 가리키는 메모리를 삭제 한 후 포인터를 NULL로 설정하는 것입니다. 코드가 NULL 포인터를 역 참조하려고하면 거의 모든 시스템에서 응용 프로그램이 충돌하게되므로 이러한 오류가 눈에 띄지 않게됩니다.

1

일어날 수있는 일을 설명하기위한 간단한 예와 일부 사람들이 언급 한 정의되지 않은 동작에 대해 설명합니다. 우리는 인쇄하기 전에 코드의 두 여분의 줄을 추가하면

는 : 그것은 귀하의 케이스 있다는

delete pTest; 

int *foo = new int; 
*foo = 42; 

cout << *pTest << endl; 

PTEST의 인쇄 값은 아주 잘, 3이 될 수 있습니다. 그러나 인쇄 된 값은 42 일 수도 있습니다. pTest 포인터가 삭제되면 메모리가 해제되었습니다. 이 때문에 foo 포인터는 이 삭제되기 전에 pTest가 가리키는 데 사용한 메모리의 동일한 위치를 가리킬 수 있습니다.

5

대답은 성능입니다.

해제 된 모든 메모리를 유효하지 않은 값 (0xCCCCCCCC, 0xDEADDEAD 등)으로 채워서 이미 해제 된 메모리에 대한 부실 포인터를 사용하려는 시도를 잡으려면 훌륭한 디버깅 도구입니다.

그러나 해제 된 메모리를 수정하면 CPU 시간이 걸리기 때문에 성능상의 이유로 OS는 해제 된 메모리 블록을 "사용 가능한"목록에 추가하고 내용을 그대로 둡니다.

관련 문제