KoreanFoodie's Study

Effective C++ | 항목 20 : '값에 의한 전달' 보다는 '상수객체 참조자에 의한 전달' 방식을 택하는 편이 대개 낫다 본문

Tutorials/C++ : Advanced

Effective C++ | 항목 20 : '값에 의한 전달' 보다는 '상수객체 참조자에 의한 전달' 방식을 택하는 편이 대개 낫다

GoldGiver 2022. 10. 25. 16:12

C++ 프로그래머의 필독서이자 바이블인, 스콧 마이어스의 Modern Effective C++ 를 읽고 기억할 내용을 요약하고 있습니다. 꼭 읽어보시길 추천드립니다!

항목 20 : '값에 의한 전달' 보다는 '상수객체 참조자에 의한 전달' 방식을 택하는 편이 대개 낫다

핵심 :

1. '값에 의한 전달' 보다는 '상수 객체 참조자에 의한 전달' 을 선호하자. 대체적으로 효율적일 뿐만 아니라 복사손실 문제까지 막아준다.
2. 이번 항목에서 다룬 법칙은 기본제공 타입 및 STL 반복자, 그리고 함수 객체 타입에는 맞지 않는다. 이들에 대해서는 '값에 의한 전달' 이 더 적절하다.

 

기본적으로 C++ 는 함수로부터 객체를 전달받거나 전달할 때 '값에 의한 전달(pass-by-value)' 방식을 사용한다. 이러한 '사본'을 만들어내는 원천은 복사 생성자인데, 이는 매우 고비용이라는 단점이 있다. 또한 복사 손실문제(slicing problem) 도 발생할 수 있는데, 다음 예시를 보자.

class Window
{
  public:
    ...
    std::string name() const;
    virtual void display() const;
};

class WindowWithScrollBars: public 
{
  public:
    virtual void display() const;
};

...

WindowWithScrollBars wwsb;
// 이 녀석을 호출하면..?
printNameAndDisplay(wwsb);

// 저런! 매개변수 전달 과정에서 '복사 생성자'가 호출되어
// WindowWithScrollBars 의 display() 함수가 잘려나간다! 
void printNameAndDisplay(Window w)
{
  std::cout << w.name();
  // 에러! Window 클래스는 display() 함수가 없다
  w.display();
}

// 이렇게 고치면 기본 클래스의 성질을 그대로 갖는다
void printnameAndDisplay(const Window& w)
{
  ...
}

객체의 크기가 작고 복사 생성자가 비싸지 않다고 무조건 '값에 의한 전달'을 사용하는 것은 좋지 못한 선택이다.

예를 들어, double 은 레지스터에 넣어 주지만, double 하나로 만들어진 사용자 정의 타입 객체는 레지스터에 넣지 않기도 한다. 이런 경우, 차라리 참조에 의한 전달을 사용해 포인터(참조자가 포인터로 구현된다)를 레지스터에 넣도록 만드는게 더 낫다.

정리하면, '값에 의한 전달'이 저비용이라고 가정해도 괜찮은 유일한 타입은 기본제공 타입, STL 반복자, 함수 객체 타입, 이렇게 세 가지 뿐이다.

 

Comments