-
Notifications
You must be signed in to change notification settings - Fork 2
2014 06 04 디폴트 생성자, 멤버 초기화 순서, 복제 생성자
Jaesoo Lim edited this page Jan 15, 2015
·
2 revisions
기존에는 디폴트 생성자에서 아무런 일도 해주지 않아도 선언부와 정의부를 분리하기 위해서는 거추장스럽게 코드를 해야 했습니다.
class MyClass {
public:
MyClass(); // 선언부
MyClass(int i);
};
MyClass::MyClass() {} // 정의부
그러나, C++11부터는 아래와 같이 간편하게 디폴트 생성자를 명시적으로 선언해 줄 수 있습니다.
class MyClass {
public:
MyClass() = default; // 명시적인 디폴트 생성자
MyClass(int i);
};
때로는 디폴트 생성자를 자동으로 만들지 않도록 해주고 싶을 경우가 있습니다. C++11에서는 아래와 같이 해주면 됩니다.
class MyClass {
public:
MyClass() = delete; // 명시적으로 삭제된 디폴트 생성자
};
생성자에서 나열해준 순서는 의미 없고, 클래서 선언부에서 나열된 순서대로 멤버가 초기화 된다.
class MyClass {
public:
MyClass();
private:
int m1;
int m2;
};
MyClass::MyClass() : m2(1), m1(m2 + 1) {}
위 코드에서 m2가 1로 초기화 되고 m1이 m2 + 1
로 초기화 될 것 같지만, 실상은 m1이 초기화되지 않은 garbage로 채워진 m2에다 1을 더해 먼저 초기화 되고, 나중에 m2가 1로 초기화 됩니다. 그런데 이 부분은 너무 걱정 안하셔도 됩니다. 컴파일러가 경고를 내줄 테니까요. ^^;
디폴트 생성자와 마찬가지로 복제 생성자도 아래와 같이 명시적으로 지정해 줄 수 있습니다.
class MyClass {
public:
MyClass(const MyClass& that) = default; // 명시적인 자동생성
MyClass(const MyClass& that) = delete; // 자동생성 방지
};
참고로, 기존에는 복제 생성자 및 대입 연산자는 방심하면 이로 인해 낭패를 보는 경우(특히, 포인터 값이 복제되어 double free를 유발하는 경우)가 있어서 아래와 같이 private으로 선언해 주어 의도치 않게 사용될 경우 컴파일할 때 오류가 나도록 하는 방법이 있습니다.
class MyClass {
private:
MyClass(const MyClass& that); // 복제 생성자
MyClass& operator=(const MyClass& that); // 대입 연산자
};
그래서 아래와 같은 매크로를 만들어서 모든 클래스에서 복제 생성자 및 대입 연산자를 기본적으로 막아두는 것이 안전합니다.
#define DISALLOW_COPY_AND_ASSIGN(T) private: T(const T&); T& operator=(const T&);
class MyClass {
DISALLOW_COPY_AND_ASSIGN(MyClass);
};