일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 참조자
- 암시적 변환
- 다형성
- 스마트 포인터
- lua
- 메타테이블
- 영화
- reference
- Vector
- UE4
- Smart Pointer
- 영화 리뷰
- 루아
- 비교 함수 객체
- 예외
- 반복자
- Effective c++
- 언리얼
- resource management class
- 티스토리챌린지
- implicit conversion
- effective stl
- 게임
- 오블완
- 상속
- operator new
- exception
- virtual function
- more effective c++
- c++
Archives
- Today
- Total
스토리텔링 개발자
[Effective C++] 20. const & 전달하기 본문
728x90
항목 20. ‘값에 의한 전달’보다는 ‘상수 객체 참조자에 의한 전달’ 방식을 택하는 편이 대개 낫다
값에 의한 전달
- C++는 함수로부터 객체를 전달받거나 함수에서 객체 전달시 ‘값에 의한 전달(pass-by-value)’ 방식을 사용한다.
- 이는 c에서 물려받은 특성 중 하나이다.
- 즉 특별히 다른 방식을 지정하지 않는 한, 함수 매개변수나 함수 반환값은 '사본'이다.
값에 의한 전달은 고비용이다.
-
class Person { ... private: string name; string address; }; class Student : public Person { ... private: string schoolName; string schoolAddress; }; bool validateStudent(Student s); .. Student plato; bool platoIsOK = validateStudent(Plato);
- validateStudent 함수에 매개변수를 전달하는 비용
- 전달 시 Student 복사 생성자 호출
- 함수 리턴 시 생성한 임시 매개변수의 Student 소멸자 호출.
- 허나 객체 내부에서 Student의 string 객체와 Person의 string 객체들도 덩달아 복사 생성 / 소멸하므로 비용은 더 증가한다.
- 해결 방법 : 매개 변수로 상수 객체에 대한 참조자(reference to const)를 전달해준다.
-
bool validateStudent(const Student& s);
- const를 붙임으로써 매개변수로 사용될 때 변화되지 않음을 보장받을 수 있다.
- 참조자를 호출하므로 생성자 / 소멸자 호출이 없다.
- 추가로, 복사 손실 문제(slicing problem)를 방지할 수 있다.
-
복사 손실 문제 (슬라이스 문제)
- 파생 클래스 객체가 기본 클래스 객체에 값으로 전달되면 발생하는 현상.
- 기본 클래스의 복사 생성자가 호출되면서 파생 클래스의 특징이 잘려나가버리고 만다.
-
class Window { public: ... string name() const; virtual void display() const; }; class WindowWithScrollBars : public Window { public: ... virtual void display() const; }; void printNameAndDisplay(Window w) { cout << w.name(); w.display(); } WindowWithScrollBars b; printNameAndDisplay(b); // 복사 손실 문제 발생! // WindowWithScrollBars의 display가 아니라 Window의 display가 호출됨. // void printNameAndDisplay(const Window& w) 로 변경하면 해결된다.
참조자의 특성
- 참조자는 포인터를 써서 구현이 된다.
- 그러므로 타입이 기본 제공 타입(int 등)일 경우 값으로 넘기는 편이 되려 효율적이다.
- 포인터의 크기와 기본 제공 타입의 크기가 그다지 큰 차이가 없기 때문이다.
반복자와 함수 객체를 구현할 때 명심할 점
- 복사 효율을 높일 것
- 복사 손실 문제에 노출되지 않도록 할 것
타입 크기가 작다고 무조건 값으로 전달하면 안 되는 이유
- 복사 생성자가 비쌀 수 있다.
- 데이터 멤버가 포인터 하나라도 포인터 멤버가 가리키는 대상까지 복사하는 작업도 따라온다.
- 수행 성능 문제가 있을 수 있다.
- 예를 들면 컴파일러 중엔 기본 제공 타입과 사용자 정의 타입을 아예 다르게 취급하는 것도 있다.
- 심지어 기본제공 타입과 사용자 정의 타입의 하부 표현구조가 같아도 그럴 수 있다는 것이 문제이다.
- 진짜 double은 레지스터에 적재하나, double 하나로만 구성된 객체는 레지스터 적재를 하지 않는다던가 하는 식이다. 하지만 포인터는 확실히 레지스터에 적재되므로 이 경우 참조 전달을 쓰는 게 낫다.
- 사용자 정의 타입은 변화에 노출되어 있다
- 언제든 구현이 변화할 수 있는 여지가 있다.
- 따라서 ‘값에 의한 전달’이 저비용이라 확실히 가정할 수 있는 타입들은 다음 세 가지 뿐이다.
- 기본 제공 타입
- STL 반복자
- 함수 객체 타입
728x90
'개발 > Effective C++' 카테고리의 다른 글
[Effective C++] 22. 데이터 멤버 확실히 숨기기 (0) | 2024.06.17 |
---|---|
[Effective C++] 21. 참조자를 리턴하면 안되는 상황 (1) | 2024.06.14 |
[Effective C++] 19. 클래스 설계 (0) | 2024.06.12 |
[Effective C++] 18. 인터페이스 설계 (1) | 2024.06.11 |
[Effective C++] 17. 스마트 포인터 생성 시 예외 문제 (0) | 2024.06.10 |
Comments