- 항목 5 : C++가 은근슬쩍 만들어 호출해 버리는 함수들에 촉각을 세우자
컴파일러가 자동적으로 생성해주는 기본 생성자(basic constructor), 복사 생성자(copy constructor), 복사 대입 연산자(copy assignment operator), 소멸자(destrucor)는 최종 결과 코드가 'legal'하고 'resonable'해야 한다. 그렇지 않으면, 컴파일러가 거부한다. 따라서 이러한 경우는 직접 기본 생성자와 복사 생성자, 복사 대입연산자, 소멸자를 만들어야 한다. 직접 위의 것들을 만든 경우, 암시적으로 위의 것들은 만들어지지 않는다.
- 암시적으로 생선되는 기본 생성자, 복사 생성자, 복사 대입 연산자, 소멸자 특징
1. public 멤버
2. inline 함수
- 암시적 복사 대입 연산자를 가질 수 없는 경우
1. C++의 참조자가 원래 자신이 참조하고 있는 것과 다른 객체를 참조하는 경우
2. 데이터 멤버가 상수 객체인 경우
3. private로 선언한 기본 클래스로부터 파생된 클래스의 경우
컴파일러는 경우에 따라 클래스에 대해 기본 생성자, 복사 생성자, 복사 대입 연산자, 소멸자를 암시적으로 만들어 놓을 수 있습니다.
class Empty {
public:
Empty() { ... } // 기본 생성자
Empty(const Empty& rhs) { ... } // 복사 생성자
~Empty() { ... } // 소멸자
Empty& operator=(const Empty& rhs) { ... } // 복사 대입 연산자
};
- 항목 6 : 컴파일러가 만들어낸 함수가 필요 없으면 확실히 이들의 사용을 금해 버리자
class Home {
public:
Home() { ... }
~Home() { ... }
private:
Home(const Home& rhs);
Home& operator=(const Home& rhs);
};
객체의 사본 생성을 막으려면 위와 같이 클래스를 만들어야 한다. Home 객체의 복사를 시도하려고 하면 컴파일러가 거부 할 것이며, 멤버 함수 혹은 friend 함수 안에서 사용하려고 해도 링커가 거부할 것입니다.
1. 함수들의 접근성을 private으로 외부로부터의 호출을 차단한다.
2. private 멤버 함수는 클래스의 멤버 함수와 friend 함수가 호출 할 수 있기 때문에 정의를 안해버리면 링크 시점에서 에러를 발생시켜 막을 수 있다.
에러 탐지는 미리 하는 것이 좋기 때문에 링크 시점 에러를 컴파일 시점 에러로 옮길 수 있다면, 옮기는게 좋다. 복사 생성자와 복사 대입 연산자를 private으로 선언하되, 이것을 별도의 기본 클래스에 넣고 이 클래스를 상속하는 방법을 사용하면 된다. 즉, 다음과 같이 사용한다.
class Uncopyable {
public:
Home() { ... }
~Home() { ... }
private:
Home(const Home& rhs);
Home& operator=(const Home& rhs);
}
class Home : private Uncopyable {
};
객체의 복사를 외부(멤버 함수, friend 함수)에서 시도하려고 할 때, 컴파일러는 Home 클래스 만의 복사 생성자와 복사 대입 연산자를 만들려고 할 것입니다. 하지만 컴파일러가 생성한 복사 함수는 기본 클래스(Uncopyable)의 대응 버전을 호출하게 되어 있습니다. 복사 함수들이 기본 클래스에서 공개되어 있지 않기 때문에 이러한 호출은 발생하지 않고 컴파일 과정에서 오류를 발생시킵니다.
컴파일러에서 자동으로 제공하는 기능을 허용치 않으려면, 대응되는 멤버 함수를 private로 선언한 후에 구현은 하지 않은 채로 두어야 합니다. boost 라이브러리인 Uncopyable과 비슷한 기본 클래스(noncopyable)를 쓰는 것도 한 방법입니다.
- 항목 7 :
- 항목 8 :
- 항목 9 :
- 항목 10 :
- 항목 11 :
- 항목 12 :
댓글 없음:
댓글 쓰기