관리 메뉴

기억을 위한 기록들

[CPP-effective] 3-4 new및 delete를 사용할 때는 형태를 반드시 맞춘다. 본문

C & CPP/Effective C++

[CPP-effective] 3-4 new및 delete를 사용할 때는 형태를 반드시 맞춘다.

에드윈H 2021. 4. 8. 16:21
string* str = new string[100];
//..
delete str;

얼핏 보면 맞는 것 같지만 str이 가리키는 100개의 string 객체들 가운데 99개는 정상적인 소멸을 거치지 못할 가능성이 크다.

 

 

new 연산자를 사용해서 표현실을 꾸미게 되면(어떤 객체를 동적 할당하면,) 두가지의 내부 동작이 진행된다.

1. 메모리가 할당된다.(operator new 라는 이름의 함수가 쓰인다.)

2. 할당 된 메모리에 대해 한 개 이상의 생성자가 호출된다.

 

반대로 delete 표현식을 사용하는 경우도 두 가지의 내부 동작이 진행된다.

1. 기존에 할당된 메모리에 대해 한개 이상의 소멸자가 호출된다.

2. 그 후 메모리가 해제된다.(operator delete라는 이름의 함수가 쓰인다.)

 

delete 연산자가 적용되는 객체는 몇 개나 될까?? 답은 바로 '소멸자가 호출되는 횟수'이다.

 

new로 힙에 만들어진 단일 객체의는 메모리 구조는 객체 배열에 대한 메모리 배치 구조와 다르다.

특히, 배열을 위해 만들어지는 힙 메모리에는 대게 배열 원소의 개수가 박혀 들어가는 게 결정적이다.

 

이 떄문에 delete 연산자는 소멸자가 몇 번 호출되는 쉽게 알 수 있다. 

반대로 단일 객체용 힙 메모리는 이런 정보가 없다.

 

쉽게 메모리 구조를 보자면,

 

string* str = new string[100]; //객체의 배열
string* str2 = new string; //한개의 객체
//..
delete str[]; //객체의 배열 삭제
delete str2; //한개의 객체 삭제

 

대괄호 쌍[] 을 붙여줘야 delete가 '포인터가 배열을 가리키고 있구나' 가정하게 된다.

 

그리고된다. 그리고 delete는 앞쪽의 메모리 몇 바이트를 읽고 이것을 배열 크기라고 해석하게 된다.그리고 그 크기의 해당하는 횟수만큼 소멸자를 호출하기 시작한다.

 

어려울 게 없고 new 표현식에 []를 쓰면 대응되는 delete에도 []를 써야 한다는 간단한 규칙이다.

 

표준 C++ 라이브러리에는 string이라던지 vector 같은 좋은 템플릿 클래스가 있기에, 잘 활용하면 동적 할당 배열이 필요해질 경우가 거의 없을 수도 있다!

 

정리

* new 표현식에 []를 쓰면 대응되는 delete 표현식에도 []를 써야하고, 마찬가지로 new 표현식에 []를 쓰지 않으면, 대응되는 delete 표현식에도 []를 쓰지 말아야 한다.