C++98에서는 특정 함수(주로 복사 생성자 / 복사 배정 연산자)를 호출하지 못하게 하기 위해 private으로 선언하고 정의는 하지 않았다. 그렇기 때문에 클라이언트는 호출 할 수 없고, 의도적으로 정의하지 않았기 때문에 호출에 실패한다.
C++11에서는 복사 생성자와 복사 배정 연산자 선언 끝에 "= delete"를 붙여 삭제된 함수를 만드는 것으로 같은 목적을 달성 할 수 있다.
삭제된 함수는 어떤 방법으로도 사용할 수 없으며, 멤버 함수나 friend 함수에서 복사하려하면 컴파일이 실패한다.
삭제된 함수는 주로 public으로 선언하는 것이 관례이며, 그 어떤 함수도 삭제 할 수 있다.
bool test(int num);
if (test('a')) ...
if (test(true)) ...
if (test(1.2f)) ...
위와 같은 예가 있을 때, 수치로 간주될 여지가 있는 형식들은 암묵적으로 int로 변환되어 정상적으로 컴파일 된다.
하지만 반드시 int값 만을 받아야 한다면 배재할 형식들에 대한 함수 중복적재를 명시적으로 삭제 해버리면 된다.
bool test(int num);
if (test('a')) = delete;
if (test(true)) = delete;
if (test(1.2f)) = delete; // char, bool, float과 double이 명시적으로 배제
삭제된 함수들도 사용할 수는 없지만 중복적재 해소 과정에서 후보로 남지만 삭제된 함수를 호출하는 과정에서 오류가 나오게 된다.
삭제된 함수의 또 다른 장점은 원치 않는 템플릿 인스턴스화를 방지한다는 점에 있다. 하지만 동일한 결과를 얻기 위해 C++98방식(private로 선언)을 사용할 수는 없다. 멤버 함수 템플릿의 한 특수화 접근 수준을 템플릿과 다른 수준으로 지정하는것이 불가능 하기 때문이다. 템플릿 특수화는 namespace범위에서 작성되어야 하지만 함수를 삭제하는 것은 접근 수준을 지정할 필요가 없기 때문에 가능하다.
class Widget{
public:
...
template<typename T>
void processPointer(T* ptr) {...}
// C++98 버전
private:
template<> void processPointer<void>(void*); // 오류
};
// C++11 버전
template<> Widget::processPointer<void>(void*) = delete; // public이지만 삭제되어 있음
Conclusion
- 정의되지 않은 비공개 함수보다 삭제된 함수를 선호하라
- 비멤버 함수와 템플릿 인스턴스를 비롯한 그 어떤 함수도 삭제가 가능하다
Reference
Effective Modern C++ 항목 11: 정의되지 않은 비공개 함수보다 삭제된 함수를 선호하라
'C++ > Effective Modern C++' 카테고리의 다른 글
iterator보다는 const_iterator를 (0) | 2020.07.06 |
---|---|
재정의 함수들은 override로 (0) | 2020.07.05 |
범위 없는 enum 보다 범위 있는 enum으로 (0) | 2020.07.02 |
typedef보다 별칭 선언 (0) | 2020.07.01 |
0과 NULL 보다 nullptr (0) | 2020.06.30 |
댓글