new 연산자를 사용하여 표현식을 꾸미게 되면(new로 어떤 객체를 동적 할당하면), 이로 인해 두 가지 내부 동작이 진행된다.
1.메모리가 할당된다.
이때 operator new라는 함수가 쓰인다(49장, 51장 참고).
2.할당된 메모리에 대해 한 개 이상의 생성자가 호출된다.
string* str1 = new string; //생성자 한 번 호출
string* str2 = new string[10]; //생성자 10번 호출
delete 표현식을 사용하는 경우 역시 두 가지의 내부 동작이 진행된다.
1.기존에 할당된 메모리에 대해 한 개 이상의 소멸자가 호출
string* str1 = new string; //생성자 한 번 호출
string* str2 = new string[10]; //생성자 10번 호출
delete str1; //소멸자 한 번 호출
delete[] str2; //소멸자 10 번 호출
2.메모리가 해제된다.
이때 operator delete라는 함수가 쓰인다(51장 참고).
여기서 생각해 봐야할 게 있는데, delete[]은 어떻게 원소의 갯수만큼 소멸자를 호출할 수 있을까?
delete 표현식은 new로 힙에 만들어진 단일 객체의 메모리 배치구조(layout)과 객체 배열에 대한 메모리 배치 구조가 다르기 때문이다. 객체 배열을 위해 만들어진 힙 메모리는 대개 배열원소의 개수가 박혀 들어간다는 차이가 있다.
그냥 예제일 뿐이지 컴파일러가 꼭 저런 식으로 구현할 필요는 없다.
결론적으로 동적 할당할 때 단일 객체로 생성했으면 delete, 객체 배열로 생성했으면 delete[]를 사용해야 한다.
typedef로 정의된 타입의 동적 배열 객체를 메모리에 생성할 때 특히 주의해야한다.
typedef string AddressLines[4];
AddressLines는 배열이다. 만약 AddressLines을 사용하여 동적 할당을 한다고 하면
string* str = new AddressLines; // string* str = new string[4];와 같음
이렇게 선언할 수 있다.
이때 주의해야 할 점은 사람눈에 보기에는 단일 객체로 보일 수 있다는 점이다. 만약 다른 사람이 이 코드를 보고 AddressLines를 타고 들어가보지 않는 이상 햇갈릴 여지가 있다.
AddressLines은 배열이기 때문에 delete역시 배열로 삭제해줘야 한다.
delete[] str; //문제 없음
delete str; //문제 있음
그렇기에 배열 타입을 typedef타입으로 만들지 않는게 좋다.
이것만은 잊지 말자
new 표현식에 []를 썼으면, 대응된느 delete 표현식에도 []를 써야한다.
마찬가지로 new 표현식에 []를 안 썼으면, 대응되는 delete 표현식에도 []를 쓰지 말아야 한다.
'서적 정리 > Effective C++' 카테고리의 다른 글
20.'값에 의한 전달'보다는 '상수객체 참조자에 의한 전달' 방식을 택하는 편이 대개 낫다 (0) | 2021.12.14 |
---|---|
19.클래스 설계는 타입 설계와 똑같이 취급하자 (0) | 2021.12.14 |
18.인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 하자 (0) | 2021.12.14 |
17.new로 생성한 객체를 스마트 포인터에 저장하는 코드는 별도의 한 문장으로 만들자 (0) | 2021.12.11 |
15.자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자 (0) | 2021.12.11 |
14.자원 관리 클래스의 복사 동작에 대해 진지하게 고찰하자 (0) | 2021.12.11 |
13.자원 관리에는 객체가 그만! (0) | 2021.12.10 |
12.객체의 모든 부분을 빠짐없이 복사하자 (0) | 2021.12.10 |
댓글