[Effective C++] Item 21: 함수에서 객체를 반환해야 할 경우에 참조자를 반환하려고 들지 말자
Item 21: 함수에서 객체를 반환해야 할 경우에 참조자를 반환하려고 들지 말자
앞서 Item20에서 다룬 참조자에 의한 전달 때문에 대부분의 부분을 참조자로 전달하려고 한다면 아직 C++에 대한 이해가 부족한 상태이다. 참조자에 의한 전달은 객체를 추가로 생성하지 않아도 된다는 이점 때문에 비용 부담이 덜하다. 이 때문에 반환시에도 참조자를 반환하려는 경우가 많다.
하지만 참조자는 결국 이름이다. 이미 존재하는 객체에 붙은 이름이기 때문에 만약 작성한 함수가 참조자를 반환하도록 만들었다면 함수가 반환하는 참조자는 반드시 이미 이름이 붙여진 참조자여야 한다.
C++에선 객체에 대한 참조자를 함수에서 반환할 수 있으면 그 객체를 직접 생성해야 한다. 함수 수준에서 객체를 만드는 방법은 딱 두 가지뿐이다. 하나는 스택에 만드는 것이고, 또 하나는 힙에 만드는 것이다.
만약 전자의 방법으로 참조자를 반환하려고 한다면, 함수안에 지역객체를 생성(이 순간 이미 생성한 셈이다.)하고 이를 반환하게 될텐데 이는 스택프레임에 의해 즉, 지역변수이기 때문에 함수를 반환하는 순간 소멸된다. 만약 이를 반환받은 함수가 해당 참조자에 접근하는 순간 미정의 동작이게 된다.
두 번째 방법으로 힙에 생성하는 경우에는 마찬가지로 함수 내에서 생성(이 순간 이미 생성한 셈)하며, new를 통해 동적할당한 이 객체의 메모리 해제의 주인도 희미해진다.
x = x * y * z;
이 코드 자체가 delete를 두번 놓치는 코드인 셈
이러한 이유로 나름의 최적화를 하기 위해 한 행동들이 부적화로 이어지게 되는 경우가 많다. 책에서 나오는 대입에 대한 비용은 최근 이동 연산자와 컴파일러 최적화로 어느정도 해결이 된다고 생각한다. 물론 사용자 정의 클래스의 경우엔 조금 다르다.
C++에서는 함수를 작성하는 정도가 있다. 이는 ‘새로운 객체를 생성해서 반환한다.’라는 개념으로 이를 명확하게 인지하고 사용하는 것이 중요하다. 아마 대부분의 프로그래머가 한번씩 경험하는 최적화에 대한 집착을 책에서 미리 알려준 것이 아닌가라는 생각이 든다.
정리
- 지역 스택 객체에 대한 포인터나 참조자를 반환하는 일, 혹은 힙에 할당된 객체에 대한 참조자를 반환하는 일, 또는 지역 정적 객체에 대한 포인터나 참조자를 반환하는 일은 그런 객체가 두 개 이상 필요해질 가능성이 있다면 절대로 하지 말 것.
댓글남기기