본문 바로가기
서적 정리/Effective C++

16.new 및 delete를 사용할 때는 형태를 반드시 맞추자

by 민돌이2 2021. 12. 11.

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 표현식에도 []를 쓰지 말아야 한다.

728x90

댓글