Effective C++ Summary - Chap 02

Chap 2. 생성자, 소멸자 및 대입 연산자

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

항목 6. 컴파일러가 만들어낸 함수가 필요 없으면 확실히 이들의 사용을 금해 버리자.

  • 기본적으로 컴파일러는 class에 대해서 기본적으로 다음 4가지를 생성한다 : constructor, copy constructor, copy assignment operator, destructor
  • 이에 따라 의도되지 않은 undefined behavior의 발생에 주의하자.
  • ex) copy of reference member
  • 컴파일러가 만들어낸 함수가 사용되지 않게 하고 싶은 경우에는 사용되지 않도록 장치를 해두자.

C++ 언어에서 기본적으로 class를 생성할 경우에 아래 네 가지 함수를 정의해준다.

  1. constructor
  2. destructor
  3. copy constructor
  4. copy assignment operator

코드로 보자면

1
2
3
4
class Emtpy(
private:
std::string& str_ref;
);

는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
class Emtpty(){
public:
Empty() {...}
EMpty(const Emtpty& rhs) {...}
~Empty() {...}
Empty &operator=(const Empty& rhs) {...}
private:
std::string& str_ref;
};

위와 같은 경우, 다음과 같은 코드를 사용하면 에러가 발생할 수 있다.

1
2
3
4
5
6
7
std::string s1("hello");
std::string s2("hi");
Empty p1(s1);
Empty p2(s2);
p1 = p2; // error occured

실제로는 아래와 같은 코드가 실행되는 것인데, reference 변수는 초기화는 가능하지만, 중간에 대입는 불가능하기 때문에, 아래와 같은 코드는 컴파일 에러가 발생하게 되는 것이 일반적이다.

1
p1.str_ref = p2.str_ref; // error

위와 같은 발생 가능성 때문에 모든 constructor, destructor, copy assignment operator, copy constructor에 대해서는 정의를 명시적으로 해 주거나, 사용되지 않도록 하는 것이 좋은 방법이다.

사용되지 않도록 하는 방법은 아래와 같다.

private 속성으로 함수를 선언해 놓고, 구현해 놓지 않는다.
이 방법은 컴파일 에러를 통해서 프로그래머의 에러를 사전에 막아주는 효과가 있다.

예를 들면 아래와 같이 해 주는 방식이다.

1
2
3
4
5
6
7
8
9
class Uncopy{
public:
Uncopy() {...};
~Uncopy() {...};
private:
Uncopy(const Uncopy&); // only declaration
Uncopy& operator=(const Uncopy&); // only declaration
};

아래처럼 class 상속을 통해서 해결하는 방법도 있다. 다만 이렇게 하면 다중상속을 고려해야 하는 상황이 생길 수 있으므로, 거기에 따른 복잡성을 고려해도 괜찮은 경우에만 사용하자.

1
2
3
4
5
6
7
8
9
10
11
12
13
class Uncopyable{
public:
Uncopyable() {...};
~Uncopyable() {...};
private:
Uncopyable(const Uncopyable&); // only declaration
Uncopyable& operator=(const Uncopyable&); // only declaration
};
class Uncopy : private Uncopyable{
...
};
Share Comments