[Effective C++] #20 값에 의한 전달, 참조자에 의한 전달
Scott Meyers의 "Effective C++"를 통해, C++ 구현에 필요한 개념들을 이해하고, 기록하기 위함입니다. 해당 항목은 4장 "설계 및 선언", 항목 20 "값의 의한 전달보다 상수 객체 참조자에 의한 전달 방식을 택하는 편이 대개 낫다"에 해당하는 내용입니다.
값에 의한 전달
C++는 함수로부터 객체를 전달받거나, 함수에게 객체를 전달할 때 '값에 의한 전달' 방식을 사용합니다. '값에 의한 전달'은 함수의 매개 변수를 전달받은 인자의 사본을 통해 초기화됩니다. 더불어 반환 값 또한 함수가 반환한 값의 사본입니다. 사본을 만드는 동작은 복사 생성자의 호출을 의미하죠. 이러한 점 때문에 '값에 의한 전달'은 비효율적인 연산이 되기도 합니다.
값에 의한 전달 예제
#include <iostream>
using namespace std;
class Person {
public:
Person();
virtual ~Person();
private:
std::string name;
std::string address;
};
class Student : public Person {
public:
Student(std::string SchoolNameInfo):
SchoolName(SchoolNameInfo){}
private:
friend bool ValidatePlato(Student A);
std::string SchoolName;
std::string SchoolAddress;
};
// 값에 의한 전달 방식 사용
bool ValidatePlato (Student A) {
if(A.SchoolName == "Plato"){
return true;
}else{
return false;
}
}
int main (){
std::string schoolNameInfo = "Plato";
Student s(schoolNameInfo);
// 값에 의한 전달
bool IsSchoolNameValid = ValidatePlato(s);
cout << IsSchoolNameValid << endl;
}
ValidatePlato 함수는 Student 객체의 schoolName이 "Plato"인지 다른 무엇인지 확인하는 함수입니다. 이 함수는 '값에 의한 전달'방식을 사용합니다. 이 방식을 사용할 때 발생하는 비용에 대해 정리해 보겠습니다. "s" 객체를 초기화하기 위해 호출되는 Student의 복사 생성자 호출 한 번, 함수 동작의 마지막에 호출되는 s의 소멸자 한 번, Student 객체 내부에 존재하는 2개의 멤버 생성, Student 클래스가 상속하는 Person 객체의 생성자 호출, Person 객체 내부에 존재하는 2개의 멤버 생성.. 등, 객체의 소멸을 위해 필요한 소멸자 호출 횟수 또한 고려하면 상당히 고비용 연산이라는 것을 알 수 있습니다. 동작 자체는 우리가 의도한 대로 정상적으로 흘러가지만, 비용면에서 비효율적입니다.
참조에 의한 전달
#include <iostream>
using namespace std;
class Person {
public:
Person();
virtual ~Person();
private:
std::string name;
std::string address;
};
class Student : public Person {
public:
Student(std::string SchoolNameInfo):
SchoolName(SchoolNameInfo){}
private:
friend bool ValidatePlato(const Student& A);
std::string SchoolName;
std::string SchoolAddress;
};
// 값에 의한 전달 방식 사용
bool ValidatePlato (const Student& A) {
if(A.SchoolName == "Plato"){
return true;
}else{
return false;
}
}
int main (){
std::string schoolNameInfo = "Plato";
Student s(schoolNameInfo);
// 값에 의한 전달
bool IsSchoolNameValid = ValidatePlato(s);
cout << IsSchoolNameValid << endl;
}
참조에 의한 전달 방식은 "복사 손실 문제"를 방지합니다. 그 이유는 참조자에 의한 전달 방식은 생성자와 소멸자가 전혀 호출되지 않기 때문입니다. 더불어, 파생 클래스 객체가 기본 클래스 객체로서 전달되는 경우, 값에 의한 전달 방식은 기본 클래스의 복사 생성자를 호출하고, 파생 클래스 객체로 동작하게 해 주는 특징들을 배제하게 됩니다. 간단하게 ValidatePlato 함수의 매개변수를 "Student s"에서 "const Student& s"로 변경해주면 되겠죠.
'값에 의한 전달'보다 '참조자에 의한 전달'이 대체적으로 효율적입니다. 기본 제공 타입 및 STL 반복자, 그리고 함수 타입에는 해당되지 않습니다.
'언어 > Effective C++' 카테고리의 다른 글
[Effective C++] #22 클래스 데이터 멤버, 접근 제어, 접근 지정자 (0) | 2022.01.28 |
---|---|
[Effective C++] #21 함수의 객체 반환, 참조자 반환 (0) | 2022.01.27 |
[Effective C++] #19 클래스 설계 (0) | 2022.01.24 |
[Effective C++] #18 인터페이스 설계 (0) | 2022.01.18 |
[Effective C++] #17 자원 관리 객체와 new 사용 (0) | 2022.01.17 |