[c++] delete []는 그것이 배열임을 어떻게 알 수 있습니까?

자, 우리는 전달 된 내용에 따라 다음 코드에서 발생하는 일이 정의되지 않은 것에 동의합니다.

void deleteForMe(int* pointer)
{
     delete[] pointer;
}

포인터는 모든 종류의 다른 일이 될 수 있으므로 무조건 수행하는 delete[]것은 정의되어 있지 않습니다. 그러나 실제로 배열 포인터를 전달한다고 가정 해 봅시다.

int main()
{
     int* arr = new int[5];
     deleteForMe(arr);
     return 0;
}

내 질문은,이 경우 포인터 배열 인 경우 누가 이것을 알고 있습니까? 언어 / 컴파일러의 관점에서 볼 arr때 배열 포인터와 단일 int에 대한 포인터 인지 여부는 알 수 없습니다 . 도대체 arr동적으로 생성 되었는지조차 알지 못합니다 . 그러나 대신 다음을 수행하면

int main()
{
     int* num = new int(1);
     deleteForMe(num);
     return 0;
}

OS는 단 하나 개의 INT를 삭제하고 그와 함께 (그 시점을 넘어 대조를 메모리의 나머지 부분을 삭제하여 ‘골라서 죽이는’의 몇 가지 유형에하지에 스마트 충분 strlen하고 비\0 문자열 조회수 0).

이 일을 기억하는 것이 누구의 일입니까? OS가 백그라운드에서 어떤 유형의 레코드를 유지합니까? (나는 무슨 일이 일어 났는지는 정의되지 않았다고 말 함으로써이 게시물을 시작했음을 알고 있지만 실제로는 ‘죽이는 행위’시나리오가 발생하지 않으므로 실제 세계에서 누군가 가 기억하고 있습니다.)



답변

컴파일러는 배열인지 알지 못하며 프로그래머를 신뢰합니다. 하나의 포인터를 삭제 int와 함께하는 것은 delete []정의되지 않은 동작이 발생할 것입니다. 두 번째 main()예제는 즉시 충돌하지 않더라도 안전하지 않습니다.

컴파일러는 어떻게 든 삭제해야하는 오브젝트 수를 추적해야합니다. 배열 크기를 저장하기에 충분히 초과 할당하여이를 수행 할 수 있습니다. 자세한 내용은 C ++ Super FAQ를 참조하십시오 .


답변

지금까지 주어진 답변으로 해결되지 않는 한 가지 질문 : 런타임 라이브러리 (OS가 아닌)가 배열의 수를 추적 할 수 있다면 왜 delete[]구문이 필요한가? 왜 싱글을 할 수 없습니까delete모든 삭제를 처리하는 데 양식을 사용할 입니까?

이에 대한 답은 C 호환 언어 인 C ++의 근본으로 거슬러 올라갑니다 (더 이상 실제로는 노력하지 않습니다) Stroustrup의 철학은 프로그래머가 사용하지 않는 기능에 대해 프로그래머가 비용을 지불 할 필요가 없다는 것입니다. 배열을 사용하지 않는 경우 할당 된 모든 메모리 청크에 대해 개체 배열 비용을 부담하지 않아도됩니다.

즉, 코드가 단순히

Foo* foo = new Foo;

할당 된 메모리 공간은의 foo배열을 지원하는 데 필요한 추가 오버 헤드를 포함하지 않아야합니다 Foo.

추가 배열 크기 정보를 전달하도록 배열 할당 만 설정되었으므로 오브젝트를 삭제할 때 해당 정보를 찾도록 런타임 라이브러리에 지시해야합니다. 우리가 사용해야하는 이유

delete[] bar;

그냥 대신

delete bar;

bar가 배열에 대한 포인터 인 경우

우리 대부분은 (나 자신을 포함하여), 몇 바이트의 메모리에 대한 까다로운 점은 요즘 기이 한 것 같습니다. 그러나 (아직 많은 수의 메모리 블록이 될 수있는 것에서) 몇 바이트를 저장하는 것이 중요한 상황이 여전히 있습니다.


답변

예, OS는 ‘배경’에 몇 가지 사항을 유지합니다. 예를 들어

int* num = new int[5];

OS는 4 개의 추가 바이트를 할당하고 할당 된 메모리의 처음 4 바이트에 할당 크기를 저장하고 오프셋 포인터를 반환합니다 (즉, 메모리 공간을 1000에서 1024까지 할당하지만 포인터는 1004를 가리킴). 할당의 크기를 저장하는 1003). 그런 다음 delete가 호출되면 포인터가 전달되기 전에 4 바이트를보고 할당 크기를 찾을 수 있습니다.

할당 크기를 추적하는 다른 방법이 있다고 확신하지만 이것이 하나의 옵션입니다.


답변

이것은 질문과 매우 유사하며 찾고있는 세부 사항이 많이 있습니다.

그러나 이것으로 추적하는 것은 OS의 일이 아닙니다. 실제로 런타임 라이브러리 또는 배열의 크기를 추적하는 기본 메모리 관리자입니다. 일반적으로 추가 메모리를 미리 할당하고 해당 위치에 배열 크기를 저장하면됩니다 (대부분 헤드 노드 사용).

이것은 다음 코드를 실행하여 일부 구현에서 볼 수 있습니다

int* pArray = new int[5];
int size = *(pArray-1);


답변

delete또는 delete[]할당 된 메모리 (메모리가 지적한)를 해제 할 수 있지만 가장 큰 차이점은 delete배열에서 배열의 각 요소의 소멸자를 호출하지 않는다는 것입니다.

어쨌든, 혼합 new/new[]하고 delete/delete[]아마도 UB입니다.


답변

배열인지 알 수 없으므로 delete[]일반 old 대신 공급해야합니다 delete.


답변

나는 이것과 비슷한 질문을했다. C에서는 malloc () (또는 다른 유사한 함수)을 사용하여 메모리를 할당하고 free ()로 삭제하십시오. malloc ()이 하나만 있는데, 이는 단순히 특정 바이트 수를 할당합니다. 하나의 free () 만 있으며, 매개 변수로 포인터를 가져옵니다.

그렇다면 왜 C에서 포인터를 free로 넘길 수는 있지만 C ++에서는 배열인지 단일 변수인지 알려 주어야합니까?

내가 배운 대답은 클래스 소멸자와 관련이 있습니다.

MyClass 클래스의 인스턴스를 할당하면 …

classes = new MyClass[3];

삭제로 삭제하면 MyClass의 첫 번째 인스턴스에 대한 소멸자 만 호출 할 수 있습니다. delete []를 사용하면 배열의 모든 인스턴스에 대해 소멸자가 호출됩니다.

이것이 중요한 차이점입니다. 단순히 표준 유형 (예 : int)으로 작업하는 경우 실제로이 문제가 표시되지 않습니다. 또한 new [] 및 delete []에서 delete를 사용하는 동작은 정의되어 있지 않으므로 모든 컴파일러 / 시스템에서 동일한 방식으로 작동하지 않을 수 있습니다.