항목 16 : new 및 delete를 사용할 때는 형태를 반드시 맞추자
아래에 적어 놓은 것에서 뭔가 잘못된 점이 보이나요?
1
2
3
|
std::string *stringArray = new std::string[100];
...
delete stringArray;
|
아무런 문제가 없어 보이지만, 100개의 string 객체 가운데 99개는 정상적인 소멸과정을 거치지 못할 가능성이 큽니다.
여러분이 new 연산자를 사용해서 표현식을 꾸미게 되면, 이로 인해 두 가지의 내부 동작이 진행됩니다. 일단 메모리가 할당됩니다. 그 다음, 할당된 메모리에 대해 한 개 이상의 생성자가 호출됩니다. delete 표현식을 쓸 경우에는 또 다른 두 가지의 내부 동작이 진행되는데, 우선 기존에 할당된 메모리에 대해 한 개 이상의 소멸자가 호출되고, 그 후에 그 메모리가 해제됩니다.
어떤 포인터에 대해 delete를 적용할 때, delete 연산자로 하여금 '배열 크기 정보가 있다'라는 정보를 알려 주어야만, delete가 '포인터가 배열을 가리키고 있구나'라고 가정하게 됩니다. 그렇지 않으면 그냥 단일 객체라고 간주하고 맙니다.
1
2
3
4
5
|
std::string *stringPtr1 = new std::string;
std::string *stringPtr2 = new std::string[100];
...
delete stringPtr1; // 객체 한 개를 삭제합니다.
delete [] stringPtr2; // 객체의 배열을 삭제합니다.
|
우리가 잊지 말아야 할 것은 new 표현식과 delete 표현식의 형태를 똑같이 맞추는 것 입니다.
이 규칙은 typedef 타입도 해당합니다.
1
|
typedef std::string AddressLines[4]; // 주소는 네 줄로 되어 있고, 각각은 string입니다.
|
AddressLines는 보다시피 배열입니다. 따라서 아래처럼 new를 사용하면,
1
|
std::string *pal = new AddressLines; // "new AddressLines"는 string*을 반환한다는 점을 잊으면 안됩니다. "new string[4]"이거든요.
|
delete 역시 배열 형태가 되어야 문단속이 제대로 됩니다.
1
2
|
delete pal; // 정상적인 소멸 과정이 이루어지지 않을 수 있습니다.
delete [] pal; // 깔끔하게 종료됩니다.
|
머리 속이 심난해지지 않으려면, 배열 타입을 typedef 타입으로 만들지 않는 것이 좋습니다. 표준 C++ 라이브러리에는 string이라든지 vector 같은 좋은 클래스 템플릿이 있어서, 잘 활용하면 동적 할당 배열이 필요해질 경우가 거의 없기 때문입니다. 위의 예제도 vector<string>타입으로 만들면 됩니다.
꼭 잊지 말아야 할 것!
new 표현식에 []를 썼으면, 대응되는 delete 표현식에도 []를 써야 합니다. 마찬가지로 new 표현식에 []를 안 썼으면, 대응되는 delete 표현식에도 []를 쓰지 말아야 합니다.
'언어 > C++' 카테고리의 다른 글
[Effective C++] 인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 하자 (0) | 2020.01.18 |
---|---|
[Effective C++] new로 생성한 객체를 스마트 포인터에 저장하는 코드는 별도의 한 문장으로 만들자 (0) | 2020.01.17 |
[Effective C++] 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자 (0) | 2020.01.15 |
[Effective C++] 자원 관리 클래스의 복사 동작에 대해 진지하게 고찰하자 (0) | 2020.01.14 |
[Effective C++] 자원 관리에는 객체가 그만! (0) | 2020.01.13 |