반응형

[C++11] default 키워드와 delete 키워드


http://jsfumato.tistory.com/10


* default 키워드

C++11에서부터는 default 키워드를 이용하여 명시적으로 default 생성자를 선언할 수 있습니다. 

C++11 이전부터 C++ 클래스는 내부를 작성하지 않아도 

기본적으로 기본생성자, 복사생성자, 대입연산자, 소멸자 네 가지 멤버함수를 생성합니다. 

**C++11부터는 기본 함수에 move 생성자와 move 대입 연산자가 추가되었습니다. 


모두가 알다시피, 위의 기본 함수들 중 생성자와 소멸자에 대해서는 중요한 규칙이 있습니다. 

어떤 종류의 생성자건, 정의된 생성자가 존재한다면, 컴파일러가 기본 생성자를 만들어주지 않는다는 것입니다. 

위와 같은 경우에 default 키워드를 사용하여 명시적으로 생성자를 만들 것을 요구할 수 있습니다.


1
2
3
4
5
6
7
8
9
10
11
12
//아래의 클래스는 복사 생성자를 private에 선언했습니다.
//이 경우 다른 기본 클래스는 생성되지 않기에 아래의 main 문은 컴파일 에러를 발생시키게 됩니다.
class MyClass
{
private:
    MyClass(const MyClass&);
};
  
int main()
{
    MyClass nc;
}


위의 경우를 해결하기 위해서는 따로 기본 클래스를 public에 선언 및 정의해주어야 합니다.

이를 더 간단화시키고 명시적으로 보이기 위해서 사용하는 것이 default 키워드입니다.

default 키워드를 사용하면 기본 생성자 또는 복사 생성자의 기본 값을 정의할 필요없이

손쉽게 default 생성자를 만들 수 있습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//default 키워드를 사용하여 명시적으로 기본 생성자를 생성했습니다
//물론 이 뿐만 아니라 명시적으로 복사생성자 또는 대입 연산자도 생성할 수 있습니다.
//이 경우 말 그대로 default한 정의를 하기 때문에 깊은 복사는 이루어지지 않습니다.
class MyClass
{
public:
    MyClass() = default;
// 위의 경우 MyClass(){}와 같습니다
private:
    MyClass(const MyClass& class) = default;
// 따로 복사생성자의 내부를 정의할 필요가 없습니다.
};
  
int main()
{
    MyClass nc;
}


* delete 키워드

delete 키워드도 이와 유사한 방법으로 사용할 수 있습니다. 

대표적으로 복사 및 대입이 불가능한 클래스를 만들고 싶을 때를 예로 들 수 있습니다. 


이전까지는 private:에 복사 생성자 및 대입 연산자를 선언하고 정의하지 않는 방식을 이용하여 

외부에서 접근하는 경우 접근 에러, 실수로 public:에 선언한 경우 링크 에러를 유발하는 방식을 사용했다면, 

C++11부터는 delete 키워드를 사용하여 명시적으로 특정 함수에 대한 정의를 금지할 수 있습니다. 


아래의 예시 코드를 살펴봅시다


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class MyClass
{
public:
    MyClass() {}
    ~MyClass() {}
  
// 아래의 생성자 및 연산자가 생성되지 않도록 명시합니다.
// private에 선언하는 방식보다 더 의도가 명확해집니다.
    MyClass(const MyClass& class) = delete;
    MyClass& operator = (const MyClass& class) = delete;
private:
// 아래의 방식이 기존에 사용되던 방식입니다.
// private에 선언하여 외부에서의 접근을 막고
// 정의부를 제외하여 실수로 public에 위치시키는 경우에도 링크 에러를 유발합니다.
// MyClass(const MyClass& class);
// MyClass& operator = (const MyClass& class);
};


delete는 생성자나 연산자 뿐만 아니라 일반 멤버 함수에도 사용할 수 있기에 

이를 응용하여 암시적 형변환이 일어나는 것을 막을 수도 있습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
class NoInteger
{
// 아래와 같이 함수를 작성하는 경우 매개변수를 int로 암시적 형변환하여 실행하는 것을 막게됩니다.
// 따라서 foo(13)을 실행하는 경우 에러가 발생합니다.
    void foo(double dparam);
    void foo(int iparam) = delete;
};
  
struct OnlyDouble
{
// 아래의 경우는 double외에는 모든 타입에 대해서 막게됩니다.
    void foo(double d);
    template<typename T> void foo(T) = delete;
};


반응형

+ Recent posts