delete []는 피연산자 배열의 크기를 어떻게 "알고"있습니까?


250
Foo* set = new Foo[100];
// ...
delete [] set;

배열의 경계를에 전달하지 않습니다 delete[]. 그러나 그 정보는 어디에 저장되어 있습니까? 표준화 되었습니까?


sourceforge.net/projects/fastmm 은 오픈 소스이며 메모리 관리자를 대체합니다. 여기에서 메모리 관리의 작동 방식과 메모리 할당 및 삭제를위한 정보의 출처를 확인할 수 있습니다.

1
FastMM은 Delphi / C ++ Builder 컴파일러에만 해당되며 C ++ 용 범용 메모리 관리자는 아닙니다. 심지어 C ++로 작성되지 않았습니다.
Remy Lebeau

답변:


181

힙에 메모리를 할당하면 할당자는 할당 한 메모리 양을 추적합니다. 이것은 일반적으로 할당 된 메모리 직전에 "헤드"세그먼트에 저장됩니다. 그렇게하면 메모리를 비울 때 할당 해제자는 메모리를 얼마나 비울 수 있는지 정확히 알 수 있습니다.


4
이것은 C ++의 배열 할당에만 적용됩니다. 다른 모든 할당은 유형의 크기에 의존합니다. 일부 라이브러리는 일반적으로 디버깅 모드에서만 모든 할당 크기를 저장합니다.
Zan Lynx

97
프로그래머가이 정보를 사용할 수없는 이유는 전혀 없습니다. 함수에 대한 포인터를 전달하고 해제 할 수는 있지만 동일한 함수에서 크기를 직접 얻으려면 추가 매개 변수를 전달해야합니다. 그게 말이 되나요?
Mark Ruzon 2016 년

26
@Mark, 이론적으로 할당자가 할당 된 블록의 크기 ( 요청 된 블록 의 크기와 다를 수 있음) 를 항상 저장할 수 있기 때문에 적은 양의 의미 가 있습니다 . 특정 할당 자 디자인은 자체 목적으로이 정보가 필요할 수도 있고, 유형 정보를 사용하여 배열이 아닌 힙 할당의 크기 등을 추적 할만큼 정교하지 않을 수도 있습니다. 할당 자에게 요청 된 크기를 저장하도록 강요하기 배열 크기를 직접 전달해야합니다.) 작은 문제 일 수 있지만 할당 자 디자인에 성능에 영향을 줄 수 있습니다.
Doug McClean

33
죄송하지만이 답변은 요점을 놓칩니다. QuantumPete가 설명한 것은 기본적으로 " free할당 할 메모리 양을 알고있는 방법"입니다. 예, 메모리 블록 크기는 "어딘가"에 의해 malloc(일반적으로 블록 자체에) 저장되므로 free알 수 있습니다. 그러나 new[]/ delete[]는 다른 이야기입니다. 후자는 기본적으로 malloc/ 위에서 작동합니다 free. new[]또한 메모리 블록에 생성 된 요소 수 (와 독립적으로 malloc)를 저장하므로 나중에 delete[]해당 숫자를 검색하고 사용하여 적절한 수의 소멸자를 호출 할 수 있습니다.
AnT

26
즉, 물리적으로 두 개의 카운터가 블록에 저장됩니다 (블록 크기 (by malloc) 및 요소 개수 (by new[])). 일반적으로 메모리 블록의 크기가 요청 된 크기의 배열에 실제로 필요한 것보다 클 수 있기 때문에 전자는 후자를 계산하는 데 사용할 수 없습니다. 또한 배열 요소 카운터는 사소한 소멸자가없는 유형에만 필요합니다. 사소한 소멸자가있는 유형의 경우 카운터는에 의해 저장 new[]되지 않으며 물론에 의해 검색되지도 않습니다 delete[].
AnT

23

컴파일러의 접근법 중 하나는 조금 더 많은 메모리를 할당하고 헤드 요소에 요소 수를 저장하는 것입니다.

수행 방법 예 :

여기

int* i = new int[4];

컴파일러는 sizeof(int)*5바이트 를 할당 합니다.

int *temp = malloc(sizeof(int)*5)

sizeof(int)바이트 에 "4"를 저장 합니다

*temp = 4;

그리고 설정 i

i = temp + 1;

따라서 i5가 아닌 4 개의 요소로 구성된 배열을 가리 킵니다.

그리고 삭제

delete[] i;

다음과 같은 방식으로 처리됩니다.

int *temp = i - 1;
int numbers_of_element = *temp; // = 4
... call destructor for numbers_of_element elements
... that are stored in temp + 1, temp + 2, ... temp + 4 if needed
free (temp)

9

정보는 표준화되지 않았습니다. 그러나이 정보를 다루는 플랫폼에서 첫 번째 요소 직전에 메모리에 저장됩니다. 따라서 이론적으로 액세스하여 검사 할 수 있지만 그만한 가치는 없습니다.

또한 delete의 배열 버전이 적절한 양의 메모리를 비워야하는 것으로 알고 적절한 소멸자 수를 호출해야한다는 것을 알기 때문에 new []로 메모리를 할당 할 때 delete []를 사용해야하는 이유도 있습니다 객체를 위해.


5

기본적으로 메모리에 다음과 같이 배열됩니다.

[정보] [요청한 ...]

여기서 info는 할당 된 메모리 양을 저장하기 위해 컴파일러에서 사용하는 구조입니다.

이것은 구현에 따라 다릅니다.


4

이것은 사양에있는 것이 아니며 구현에 따라 다릅니다.


3

C ++ 표준에서 컴파일러에 따라 정의됩니다. 이것은 컴파일러의 마술을 의미합니다. 하나 이상의 주요 플랫폼에서 사소한 정렬 제한으로 인해 중단 될 수 있습니다.

에 의해 delete[]반환 된 포인터에 대해서만 정의되며 new[],에 의해 반환 된 포인터와 같지 않을 수 있음을 인식함으로써 가능한 구현에 대해 생각할 수 있습니다 operator new[]. 와일드에서 한 구현은에서 반환 된 첫 번째 int에 배열 수를 저장하고 그 이후로 포인터 오프셋 operator new[]new[]반환하는 것입니다. (이것이 사소한 정렬이 깨질 수있는 이유 new[]입니다.)

있음을 알아 두셔야합니다 operator new[]/operator delete[]! = new[]/delete[].

또한 이것은 C가 할당 한 메모리 크기를 알고있는 방식과 직교합니다 malloc.


2

'삭제'할 배열은 'new'연산자를 한 번만 사용하여 만들어야했기 때문입니다. 'new'작업은 해당 정보를 힙에 넣어야합니다. 그렇지 않으면, 새로운 추가 사용은 힙이 끝나는 위치를 어떻게 알 수 있습니까?


0

표준화되지 않았습니다. Microsoft 런타임에서 새 연산자는 malloc ()을 사용하고 삭제 연산자는 free ()를 사용합니다. 따라서이 설정에서 귀하의 질문은 다음과 같습니다. free ()는 블록의 크기를 어떻게 알 수 있습니까?

C 런타임과 같은 장면 뒤에 약간의 부기가 있습니다.


5
사실이 아니다. free를 호출하기 전에 delete []가 먼저 소멸자를 호출해야합니다. 이를 위해서는 총 할당 크기가 충분하지 않습니다. 실제로 new []와 delete []는 VC ++에서 일반 및 파괴 된 유형에 대해 다르게 작동합니다.
Suma

0

이것은 처음에 생각하는 것보다 더 흥미로운 문제입니다. 이 답변은 가능한 한 가지 구현에 관한 것입니다.

첫째, 어떤 수준에서 시스템은 메모리 블록을 '빈'하는 방법을 알아야하지만 기본 malloc / free (new / delete / new [] / delete [] 일반적으로 호출)는 항상 정확히 얼마나 많은 메모리를 기억하지는 않습니다 요청하면 반올림 될 수 있습니다 (예를 들어 4K 이상이면 종종 다음 4K 크기의 블록으로 올림됩니다).

그러므로, 메모리 블록의 크기를 얻을 수 있더라도, 새로운 메모리에 얼마나 많은 값이 있는지를 알려주지는 않습니다. 따라서 우리는 몇 개의 값이 있는지 알려주는 여분의 정수를 저장해야합니다.

예외적으로, 생성중인 타입에 소멸자가 없다면 delete []는 메모리 블록을 비우는 것 외에는 아무것도 할 필요가 없으므로 아무것도 저장할 필요가 없습니다!

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