가독성을 위해 default와 delete 키워드를 사용하자
[배경]
클래스 작성 시 우리가 직접 작성하지 않아도 기본적으로 컴파일러가 생성해주는 것들이 있다. 그 대표적인 예로 기본 생성자, 기본 소멸자, 기본 복사생성자, 기본 대입 연산자 등이 그렇다.
기본적으로 컴파일러가 생성해준 복사생성자와 대입 연산자는 객체 복사 시 얕은 복사를 수행한다. 물론 멤버 변수가 값 형식일 경우 또는 주소를 그대로 복사해도 될 경우 깊은 복사를 하지 않아도 된다. 이 경우는 컴파일러가 알아서 만들어주는 것들을 써도 되기에 굳이 복사 생성자와 대입 연산자를 작성하지 않아도 되는 경우이다.
하지만 이는 코드를 짠 사람만 한눈에 이해할 수 있다. 게다가 코드가 매우 길다면 작성자 마저도 헷갈릴 수 있다. 또한 코드를 보는 다른 사람의 입장에서 생각해 보자. 외부인은 이 코드를 분석하지 않는 이상, 코드를 작성한 사람이 생성자를 실수로 구현하지 않은 건지 의도적으로 구현하지 않은 건지 알아채기 어려울 수 있다. 즉 의도가 명확하지 않다는 단점이 있다. 프로그래밍에선 뭐든 명확한 것이 좋기 때문에 가능한 명확히 해주는 것이 모두에게 좋다.
[default 키워드]
C++ 11에선 default 라는 키워드를 통해 이 의도를 명확히 전달해줄 수 있다. default는 다음과 같이 사용한다.
class Foo
{
public:
...
Foo(const Foo& other) = default;
Foo& operator=(const Foo& rhs) = default;
...
};
위와 같이 default 키워드를 사용하면 컴파일러가 만들어준 기본 복사 생성자 및 기본 대입 연산자를 사용하겠다는 뜻이다. 컴파일러에겐 의미가 동일하지만, 이는 "깊은 복사를 하지 않아도 되므로 컴파일러가 구현해주는 디폴트 함수 및 연산자를 사용하겠다" 라고 명시적으로 표시해주는 것이다. 코드를 읽는 사람은 이 클래스가 얕은 복사를 해도 된다는 명확한 의도를 받을 수 있다.
기본 생성자와 소멸자도 마찬가지이다. 메모리 할당 또는 해제가 필요없거나 기본 생성자와 소멸자를 그대로 사용해도된다면 default 키워드를 통해 명시적으로 "디폴트 값을 사용하겠다" 라고 표시해주는 것이 좋다.
[delete 키워드]
그럼 반대로 컴파일러가 생성해주는 디폴트 값이 필요없어 생성되지 않도록 하고 싶을 수도 있다. delete 키워드는 컴파일러가 자동으로 만들어주는 것을 막는 것이다.
예를 들어 해당 클래스 객체는 복사가 불가능하도록 만들고 싶다고 해보자. delete 키워드를 모른다면 다음과 같이 private 영역으로 옮겨서 클래스 외부에서 사용하지 못하도록 일종의 트릭을 사용할 수 있다. 하지만 이는 복사 생성자와 대입 연산자를 생성하지 않은 것이 아니라 생성 후 사용하지 못하도록 막아놓은 것이다. 완전 깔끔한 해결법이라고 볼 순 없다.
class Foo
{
public:
...
private:
Foo(const Foo& other) {}
Foo& operator=(const Foo& rhs) {}
...
};
이럴 경우 다음과 같이 delete 키워드를 사용하면 명시적으로 복사를 하지 않겠다는 의도를 줄 수 있다.
class Foo
{
public:
...
Foo(const Foo& other) = delete;
Foo& operator=(const Foo& rhs) = delete;
...
};
delete 키워드가 선언된 복사 생성자를 호출하려고 해보면 다음과 같은 에러 메세지를 준다.
해석해보면 "MyClass 클래스의 복사 생성자가 참조될 수 없습니다. 삭제된 함수입니다" 라고 명확하게 에러 메세지를 전달해준다. 참고로 이 메세지는 대충이라도 기억해 두면 좋다. 가끔 라이브러리의 클래스를 사용할 때 다음과 같은 에러가 뜨면 무엇 때문에 발생한 에러인지 이해할 수 있기 때문.
'C,C++ > C++' 카테고리의 다른 글
[C++] 범위 내의 난수 생성하기 | 비결정적 난수 (0) | 2020.03.05 |
---|---|
[C++] 멤버 변수의 오프셋을 계산해주는 offsetof 매크로 (0) | 2020.02.29 |
[C++] static_assert 매크로에 대해 알아보자. (0) | 2020.02.28 |
[C++] 스택과 힙 메모리, "RAII"라는 패턴 및 기법에 대해 알아보자 (0) | 2020.02.23 |
[C++] 추상 클래스와 순수 가상함수를 알아보자(feat. 인터페이스, 다중상속) (0) | 2020.02.20 |
댓글