항목 16 new와 delete를 사용할 때는 형태를 반드시 맞추자
16.1 객체와 객체 배열의 메모리 구조
new 표현식을 사용해서 어떤 객체를 동적 할당하면 두 가지 내부 동작이 진행된다. 일단 operator new 함수가 사용되어 메모리가 할당된다. 그다음, 할당된 메모리에 대해 한 개 이상의 생성자가 호출된다. 반면, delete 표현식을 사용하면 또 다른 두 가지 내부 동작이 진행되는데, 우선 할당된 메모리에 대해 한 개 이상의 소멸자가 호출되고, 그 후에 operator delete 함수가 사용되어 메모리가 해제된다.
new로 힙에 만들어진 객체의 메모리 배치 구조(layout)는 객체 배열의 메모리 배치 구조와 다르다. 특히, 배열을 위해 만들어지는 힙 메모리에는 대개 배열의 원소 개수, 즉 배열의 크기가 포함되는데, 이 때문에 delete 연산자는 소멸자가 몇 번 호출될지 알 수 있다. 반면, 객체를 위한 힙 메모리에는 이런 정보가 없다.
16.2 new에는 delete, new[]에는 delete[]
여러분은 어떤 포인터에 대해 delete를 적용할 때 delete 연산자에게 배열의 크기 정보가 포함되어 있다는 것을 알려 줄 의무를 지고 있다. 이때 대괄호 쌍([])을 delete 뒤에 반드시 붙인다. 그제야 delete는 이 포인터가 객체를 가리키지 않고 객체 배열을 가리키고 있다고 간주한다.
std::string* stringPtr1 = new std::string;
std::string* stringPtr2 = new std::string[10];
...
delete stringPtr1; /* 객체를 삭제합니다. */
delete[] stringPtr2; /* 객체 배열을 삭제합니다. */
어려울 것 하나 없다. new 표현식에 []를 썼으면 여기에 대응되는 delete 표현식에도 []를 쓴다. new 표현식에 []를 안 썼으면 대응되는 delete 표현식에도 []를 안 쓰면 된다.
이 규칙은 typedef 애호가도 알아둘 가치가 있다. typedef로 정의된 어떤 타입의 객체 혹은 객체 배열을 메모리에 생성하려고 new를 썼을 때 어떤 delete를 적어야 하는지에 대한 책임을 typedef 타입 작성자가 져야 하는 의미로 볼 수 있다.
typedef std::string addressLines[5];
std::string* pal new addressLine; /* new addressLine은 new string[4]입니다. */
...
delete pal; /* 안 됩니다. 잘못된 삭제입니다. */
delete[] pal; /* 올바른 삭제입니다. */
예를 들어, 어떤 typedef 타입이 다음과 같이 정의되어 있다고 가정해보자. addressLines는 보다시피 배열이므로 new를 사용하면 delete 역시 배열 형태([])가 되어야 한다.
NOTE
① new 표현식에 []를 썼으면 대응되는 delete 표현식에도 []를 써야 한다. 마찬가지로 new 표현식에 []를 안 썼으면 대응되는 delete 표현식에도 []를 쓰지 말아야 한다.
'Object Oriented Programming(C++) > Effective C++' 카테고리의 다른 글
Effective C++ | 항목 18 인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 하자 (0) | 2022.02.03 |
---|---|
Effective C++ | 항목 17 new로 생성한 객체를 스마트 포인터에 저장하는 코드는 별도의 한 문장으로 만들자 (0) | 2022.01.25 |
Effective C++ | 항목 15 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자 (0) | 2022.01.25 |
Effective C++ | 항목 14 자원 관리 클래스의 복사 동작을 고찰하자 (0) | 2022.01.24 |
Effective C++ | 항목 13 자원은 객체로 관리하자 (0) | 2022.01.23 |
댓글