본문 바로가기
Object Oriented Programming(C++)/Effective C++

Effective C++ | 항목 05 C++가 은근슬쩍 만들어 호출해버리는 함수들에 촉각을 세우자

by continue96 2021. 8. 26.

이펙티브 C++ 항목 05

 

항목 05 C++가 은근슬쩍 만들어 호출해버리는 함수들

5.1 컴파일러가 선언하는 디폴트 멤버 함수

  • 컴파일러가 기본으로 선언하는 멤버 함수는 다음과 같다.
    • 생성자(constructor)
    • 복사 생성자(copy constructor)
    • 소멸자(destructor)
    • 복사 대입 연산자(copy assignment operator)
    • 컴파일러가 만드는 함수는 모두 기본형(default)이고 public 멤버이며 inline 함수다.
class Empty { };

class Empty {
public:
	Empty() { ... };// 디폴트 생성자
	Empty(const Empty& rhs) { ... };// 디폴트 복사 생성자
	~Empty() { ... };// 디폴트 소멸자
	Empty& operator=(const Empty& rhs) { ... };// 디폴트 복사 대입 연산자
};

Empty e1;// 디폴트 생성자, 디폴트 소멸자 조건
Empty e2(e1);// 디폴트 복사 생성자 조건
e2 = e1;// 디폴트 복사 대입 연산자 조건

 

5.1.1 디폴트 생성자와 디폴트 소멸자

  • 디폴트 생성자디폴트 소멸자는 컴파일러에게 배후의 코드를 깔 수 있는 자리를 마련한다.
    • 부모 클래스 및 비정적(non-static) 데이터 멤버의 생성자와 소멸자를 호출하는 코드가 이곳에 생긴다.
    • 부모 클래스가 가상 소멸자로 되어있으면 역시 가상 소멸자로 만들어진다.

 

5.1.2 디폴트 복사 생성자와 디폴트 복사 대입 연산자

  • 디폴트 복사 생성자디폴트 복사 대입 연산자는 원본 객체의 비정적 데이터를 사본 객체로 복사한다.
template<typename T>
class NamedObject {
public:
	// 사용자가 정의한 생성자
	NamedObject(const string& name, const T& value)
		: nameValue(name), objectValue(value) {
		cout << "NamedObject 생성자" << endl;
	}
	
	// 디폴트 복사 생성자
	NamedObject(const NamedObject& src)
		: nameValue(src.nameValue), objectValue(src.objectValue) { }

private:
	string nameValue;
	T objectValue;
};

NamedObject<int> no1("Smallest Prime Number", 2);
NamedObject<int> no2(no1);// 디폴트 복사 생성자를 호출합니다.

 

  • 디폴트 복사 생성자와 디폴트 복사 대입 연산자는 코드가 적법(legal) 하고 이치에 닿아야(reasonable)만 자동으로 생성된다.
    • 데이터 멤버가 참조자인 경우, C++의 참조자는 원래 자신이 참조하고 있는 것과 다른 객체를 참조할 수 없다. 
    • 데이터 멤버가 상수인 경우, 상수 멤버를 수정하는 것은 문법에 어긋난다.
    • 참조자와 상수 데이터 멤버를 처리할 수 없으므로 아예 컴파일을 거부한다. 
template<typename T>
class NamedObject {
public:
	NamedObject(string& name, const T& value) : nameValue(name), objectValue(value) {
		cout << "NamedObject 생성자" << endl;
	}

private:
	string& nameValue;// 레퍼런스 데이터 멤버
	const T objectValue;// const 데이터 멤버
};

string newDog("Persephone");
string oldDog("Satch");
NamedObject<int> p(newDog, 2);
NamedObject<int> s(oldDog, 36);
p = s;// 컴파일 오류!

 

NOTE
① 컴파일러는 경우에 따라 클래스에 기본 생성자, 소멸자, 복사 생성자, 복사 대입 연산자를 암시적으로 만들어 놓을 수 있다.

댓글