C ++에서 포인터 삭제


92

컨텍스트 : 저는 포인터 주위에 머리를 감 으려고 노력하고 있습니다. 우리는 몇 주 전에 학교에서 그들을 보았고 오늘 연습하는 동안 나는 어리석은 일을 만났습니다. 문제, 그것은 당신에게 매우 간단 할 수 있지만 프로그래밍 경험이 거의 없습니다.

나는 포인터 삭제에 관한 몇 가지 질문을 보았지만 모두 '간단한'포인터가 아닌 클래스 삭제와 관련이있는 것 같습니다 (또는 적절한 용어가 무엇이든간에), 여기에 내가 시도하는 코드가 있습니다. 운영:

#include <iostream>;

using namespace std;

int main() {
  int myVar,
      *myPointer;

  myVar = 8;
  myPointer = &myVar;

  cout << "delete-ing pointers " << endl;
  cout << "Memory address: " << myPointer << endl;

  // Seems I can't *just* delete it, as it triggers an error 
  delete myPointer;
  cout << "myPointer: " << myPointer << endl;
  // Error: a.out(14399) malloc: *** error for object 0x7fff61e537f4:
  // pointer being freed was not allocated
  // *** set a breakpoint in malloc_error_break to debug
  // Abort trap: 6

  // Using the new keyword befor deleting it works, but
  // does it really frees up the space? 
  myPointer = new int;
  delete myPointer;
  cout << "myPointer: " << myPointer << endl;
  // myPointer continues to store a memory address.

  // Using NULL before deleting it, seems to work. 
  myPointer = NULL;
  delete myPointer;
  cout << "myPointer: " << myPointer << endl;
  // myPointer returns 0.

}

그래서 내 질문은 다음과 같습니다.

  1. 첫 번째 사례가 작동하지 않는 이유는 무엇입니까? 포인터를 사용하고 삭제하는 가장 간단한 사용법은 무엇입니까? 오류는 메모리가 할당되지 않았지만 'cout'이 주소를 반환했다고 말합니다.
  2. 두 번째 예에서는 오류가 발생하지 않지만 myPointer 값을 cout하면 여전히 메모리 주소가 반환됩니까?
  3. # 3이 실제로 작동합니까? 나에게 일하는 것 같고 포인터가 더 이상 주소를 저장하지 않습니다. 이것이 포인터를 삭제하는 적절한 방법입니까?

긴 질문에 대해 죄송합니다. 가능한 한 명확하게 만들고 싶었습니다. 다시 말하지만 프로그래밍 경험이 거의 없기 때문에 누군가가 평신도의 용어를 사용하여 대답 할 수 있다면 대단히 감사하겠습니다!


16
첫 번째 예가 보이지 않는 이유는 그것이 잘못 되었기 때문입니다. delete당신 만 new. 포인터를 삭제 한 후 포인터가 NULL로 설정 될 필요도 없습니다. 안전을 원하면 스마트 포인터를 사용하여 메모리를 확보하고 무언가를 잡고 있지 않을 때 액세스하려고하면 오류를 발생시킵니다.
chris

흠 좋아요. 스마트 포인터가 뭔지 잘 모르겠지만 조사해 보겠습니다. 감사합니다!
leopic

1
간단히 말해서, 그들은 내가 설명한대로합니다. 새로운 것을 담기 위해 당신은 전화를 걸어 reset오래된 것을 풀어줍니다. 교체하지 않고 해제하려면을 호출하십시오 release. 범위를 벗어나면 파괴되고 어떤 유형인지에 따라 메모리를 해제 할 수 있습니다. std::unique_ptr한 명의 소유자만을위한 것입니다. std::shared_ptr마지막 소유자가 리소스 소유를 중지하면 해제됩니다. 또한 예외적으로 안전합니다. 리소스를 할당 한 후 예외가 발생하면 리소스가 제대로 해제됩니다.
chris

답변:


168

1 및 2

myVar = 8; //not dynamically allocated. Can't call delete on it.
myPointer = new int; //dynamically allocated, can call delete on it.

첫 번째 변수는 스택에 할당되었습니다. new연산자를 사용하여 동적으로 (힙에서) 할당 한 메모리에서만 delete를 호출 할 수 있습니다 .

삼.

  myPointer = NULL;
  delete myPointer;

위는 전혀 아무것도 하지 않았습니다 . 포인터가 NULL을 가리키고 있으므로 아무것도 해제하지 않았습니다.


다음은 수행하면 안됩니다.

myPointer = new int;
myPointer = NULL; //leaked memory, no pointer to above int
delete myPointer; //no point at all

NULL을 가리키고 누수 된 메모리 (할당 한 새 정수)를 남겼습니다. 가리키는 메모리를 해제해야합니다. new int더 이상 할당 된 항목에 액세스 할 수있는 방법이 없으므로 메모리 누수가 발생합니다.


올바른 방법 :

myPointer = new int;
delete myPointer; //freed memory
myPointer = NULL; //pointed dangling ptr to NULL

더 나은 방법 :

C ++를 사용하는 경우 원시 포인터를 사용 하지 마십시오 . 대신 약간의 오버 헤드로 이러한 일을 처리 할 수있는 스마트 포인터 를 사용하십시오 . C ++ 11에는 여러 .


13
<pedantry> "On the stack"은 구현 세부 사항입니다. C ++에서는 언급을 눈에 띄게 피합니다. 더 정확한 용어는 "자동 저장 기간 포함"입니다. (C ++ 11, 3.7.3) </
pedantry

4
감사합니다. a) 무엇이 잘못되었는지 설명하고 b) 모범 사례를 제공하기 위해 답변을 선택했습니다. 감사합니다!
leopic

6
@Tqn 맞지 않습니다. delete myPointer할당을 해제 *myPointer합니다. 맞아요. 그러나 myPointer해제 된 메모리 위치를 계속 가리키며 UB이므로 사용해서는 안됩니다. 범위가 끝난 후에는 처음에 지역 변수 인 경우에만 액세스 할 수 없습니다.
Anirudh Ramanathan 2014

2
@DarkCthulhu 감사합니다! (말 그대로) new매일 무언가를 배웁니다 . (나는 치즈 맛이 나는거야!)
Tqn

1
@AmelSalibasic 스택의 변수와 관련된 메모리는 범위를 벗어난 경우에만 해제됩니다. 할당하면 NULL나중에 오용 되는 것을 방지 할 수 있습니다.
Anirudh Ramanathan 2014 년

23

포인터가 어떻게 작동하는지 완전히 이해하지 못하고 있다고 생각합니다.
어떤 메모리를 가리키는 포인터가있을 때 이해해야 할 세 가지 다른 점이 있습니다
.-포인터 (메모리)가 가리키는 "무엇"
이 있습니다.-이 메모리 주소
-모든 포인터가 메모리를 삭제할 필요는 없습니다. 동적으로 할당 된 메모리를 삭제해야합니다 (사용 된 new연산자).

상상해보십시오.

int *ptr = new int; 
// ptr has the address of the memory.
// at this point, the actual memory doesn't have anything.
*ptr = 8;
// you're assigning the integer 8 into that memory.
delete ptr;
// you are only deleting the memory.
// at this point the pointer still has the same memory address (as you could
//   notice from your 2nd test) but what inside that memory is gone!

그랬을 때

ptr = NULL;
// you didn't delete the memory
// you're only saying that this pointer is now pointing to "nowhere".
// the memory that was pointed by this pointer is now lost.

C ++를 사용 delete하면 가리키는 포인터 를 시도 할 수 null있지만 실제로는 아무 작업도 수행하지 않고 오류를주지 않습니다.


2
고마워요, 이것은 매우 도움이되었습니다. 모든 포인터를 삭제해야한다고 생각했습니다. 새로운 포인터에만 해당한다는 것을 몰랐습니다. 감사합니다.
leopic

13

포인터는 삭제할 필요가 없다는 점에서 일반 변수와 유사합니다. 함수 실행 종료 및 / 또는 프로그램 종료시 메모리에서 제거됩니다.

그러나 다음과 같이 포인터를 사용하여 메모리 '블록'을 할당 할 수 있습니다.

int *some_integers = new int[20000]

이것은 20000 정수에 대한 메모리 공간을 할당합니다. 스택의 크기가 제한되어 있고 스택 오버플로 오류없이 'ints'의 큰로드를 엉망으로 만들고 싶을 수 있기 때문에 유용합니다.

new를 호출 할 때마다 프로그램 끝에서 '삭제'해야합니다. 그렇지 않으면 메모리 누수가 발생하고 할당 된 메모리 공간이 다른 프로그램에서 사용할 수 있도록 반환되지 않기 때문입니다. 이것을하기 위해:

delete [] some_integers;

도움이되기를 바랍니다.


1
다른 프로그램에서 사용할 수 있도록 할당 된 메모리가 반환되지만 프로그램 실행이 완료된 후에 만 ​​추가하고 싶습니다.
sk4l

7

C ++에는 새로운 규칙 이있을 때마다 delete가 있습니다.

  1. 첫 번째 사례가 작동하지 않는 이유는 무엇입니까? 포인터를 사용하고 삭제하는 가장 간단한 사용법은 무엇입니까? 오류는 메모리가 할당되지 않았지만 'cout'이 주소를 반환했다고 말합니다.

new는 호출되지 않습니다. 따라서 cout이 인쇄하는 주소는 myVar의 메모리 위치 주소이거나이 경우 myPointer에 할당 된 값입니다. 작성 :

myPointer = &myVar;

당신은 말한다 :

myPointer = myVar의 데이터가 저장되는 주소

  1. 두 번째 예에서는 오류가 발생하지 않지만 myPointer 값을 cout하면 여전히 메모리 주소가 반환됩니까?

삭제 된 메모리 위치를 가리키는 주소를 반환합니다. 먼저 포인터를 만들고 값을 myPointer에 할당하고 두 번째로 포인터를 삭제하고 세 번째로 인쇄하기 때문입니다. 따라서 myPointer에 다른 값을 할당하지 않으면 삭제 된 주소가 그대로 유지됩니다.

  1. # 3이 실제로 작동합니까? 나에게 일하는 것 같고 포인터가 더 이상 주소를 저장하지 않습니다. 이것이 포인터를 삭제하는 적절한 방법입니까?

NULL은 0이고 0을 삭제하므로 아무것도 삭제하지 않습니다. 그리고 다음과 같이했기 때문에 0을 인쇄하는 논리입니다.

myPointer = NULL;

다음과 같습니다.

myPointer = 0;

4
  1. 스택에 할당 된 변수를 삭제하려고합니다. 너는 이것을 못해
  2. 포인터를 삭제한다고해서 실제로 포인터가 파괴되지는 않으며 점유 된 메모리 만 OS에 반환됩니다. 메모리가 다른 변수에 사용되거나 조작 될 때까지 액세스 할 수 있습니다. 따라서 삭제 후 포인터를 NULL (0)로 설정하는 것이 좋습니다.
  3. NULL 포인터를 삭제해도 아무것도 삭제되지 않습니다.

2
int value, *ptr;

value = 8;
ptr = &value;
// ptr points to value, which lives on a stack frame.
// you are not responsible for managing its lifetime.

ptr = new int;
delete ptr;
// yes this is the normal way to manage the lifetime of
// dynamically allocated memory, you new'ed it, you delete it.

ptr = nullptr;
delete ptr;
// this is illogical, essentially you are saying delete nothing.

1
또한 스택 프레임 youtube.com/watch?v=bjObm0hxIYY 및 포인터에 대한 youtube.com/watch?v=Rxvv9krECNw 에 대한 이 강의를 확인하십시오 .
캐스퍼 베이어
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.