본문 바로가기

Effective C++

[EC++] 항목 20. 값에 의한 전달보다는 상수 객체 참조자에 의한 전달 방식을 택하는 편이 대게 낫다.

  우선 이번 항목에서는 쟁점이라고 할 수 있는 것은 Pass by Value(Call by value) 의 두가지 문제점을 제기 하는데요. 첫번째는 바로 고비용 문제 입니다. 
  기본적으로 C++는 함수로부터 객체를 전달받거나 함수에 객체를 전달할 때 값에 의한 전달 방식을 사용하는데요. 특별히 다른 방식을 지정하지 않는 한, 함수 매개변수는 실제 인자의 '사본'을 통해 초기화되며, 어떤 함수를 호출 한 쪽은 그 함수가 반환한 값의 사본을 돌려받습니다. 이들 사본을 만들어 내는 곳이 바로 복사 생성자인데, 이런 점 때문에 고비용의 연산이 되기도 합니다.

  한번 예제를 보면서 알아 보도록 하겠습니다. 
실행결과 :


 위의 예제를 실행해 보면 Pass by Value방식에는 문제가 없습니다. 실행을 해보면 생성자와 소멸자가 제대로 실행되는게 보입니다. 하지만, student 객체 생성시 student 객체에는 string 객체 두개가 멤버로 들어 있기 때문에, cout으로 명시적으로 보여준 생성자 , 소멸자 생성, 소멸의 과정 뿐만 아니라, student 객체가 생성될때마다 이들 string 객체 두개도 덩달아 생성되고 소멸이 되고, 이때마다 생성자, 소멸자를 호출 해야 하므로, 고비용의 문제가 발생하게 됩니다. 

그래서 이런 고비용 문제를 피하기 위한 방법이 있습니다. 바로 "상수 객체에 대한 참조자"로 전달하는 방법입니다. (Reference to const바로 Call by Reference 방법에 상수화를 더한 것이죠. 

방법은 bool validatestudent부분에서 괄호 부분을 (const student &stu); 이렇게 바꾸면 됩니다.이 방식의 좋은점은 새로 만들어지는 객체 같은 것이 없기 때문에, 생성자와 소멸자 호출도 당연히 없습니다.(Call by Reference의 장점과 같죠) 이로서 고비용의 부담문제를 해결 할수 있습니다. 

또한 여기서 주목해야 할 점은 const 상수 선언인데, 그 전에  call by value와 call by referecne가 가진 특징을 다시 한번 상기 시켜 봅시다. (제가 이미 포스팅한  링크 참조)


 우리가 사용하려는 참조자에 의한 전달 방법으로 고비용 문제는 해결했지만, 원본값이 변경될 우려가 있으므로, const를 씀으로서 이런 변화로부터 안전하게 보호를 해주는 것입니다. 

두번째 문제는 바로 복사손실 (slicing problem) 문제 입니다. Call by Reference를 씀으로 인해서 바로 복사손실을 방지할 수 있는 장점이 있는데요. 우선 예제 코드를 보겠습니다. 예제 코드는 윈도우 클래스로 만들어지는 객체는 이름을 갖고 있고, 이 이름은 name 멤버 함수로 얻어내고,  display 함수로 이를 화면표시를 해주는 예제 인데요. 

 위 함수들을 파생클래스 객체를 넘긴다면 , 매개변수 w가 생성되기는 하지만, 어떤 타입의 객체가 넘어가든 window 클래스 객체의 면모만을 갖게 되므로, 가상함수를 사용했음에도 불구하고 windowwithscroolbars::display는 출력되지 않는 것이 바로 문제가 됩니다. 여기도 마찬가지로 문제를 해결하기 위해서는 상수 객체에 대한 참조자로 전달 하도록 만들면 됩니다. 
이렇게 만들면 어떠한 객체 타입이 넘어와도 그 고유 성질을 그대로 갖게 되므로 복사손실은 발생하지 않습니다. 

항목 20의 제목에서 나타난거와 같이 상수객체 참조자에 의한 전달방식이 택하는 편이 고비용, 복사손실 두개의 문제해결능력으로 봐서는 대게는 나은 결과를 보여주지만, 기본제공 타입, STL반복자 그리고 함수 객체 타입, 이 세가지는 이전부터 값으로 전달되도록 설계해 왔기 때문에 이 두가지 경우에는 pass by Value 방법을 사용하는 것이 더 적절합니다. 

 ※ 상황에 따라 적절하게 Call by Value , Call by Reference를 쓰자~!!!