Program Tip

C ++ 11에서 명시 적으로 삭제 된 멤버 함수를 사용하여 복사 할 수없는 기본 클래스에서 상속 할 가치가 있습니까?

programtip 2020. 12. 11. 19:19
반응형

C ++ 11에서 명시 적으로 삭제 된 멤버 함수를 사용하여 복사 할 수없는 기본 클래스에서 상속 할 가치가 있습니까?


C ++ 11에서 명시 적으로 삭제 된 멤버 함수를 사용하여 복사 할 수없는 기본 클래스에서 상속 할 가치가 있습니까?

개인 또는 삭제 복사 생성자와 복사 할당 (예 :)이있는 기본 클래스를 비공개로 상속하는 트릭에 대해 이야기하고 boost::noncopyable있습니다.

질문 에 제시된 이점이 C ++ 11에도 적용됩니까?


일부 사람들이 C ++ 11에서 클래스를 복사 불가능하게 만드는 것이 더 쉽다고 주장하는 이유를 모르겠습니다.

C ++ 03에서 :

private:
    MyClass(const MyClass&) {}
    MyClass& operator=(const MyClass&) {}

C ++ 11에서 :

MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass&) = delete;

편집하다:

많은 사람들이 지적했듯이 개인 복사 생성자와 복사 할당 연산자에 대해 빈 본문 (예 : {})을 제공하면 클래스 자체가 오류없이 해당 연산자를 호출 할 수 있기 때문에 실수였습니다. 처음에는 {}를 추가하지 않고 시작했지만 어리석은 이유로 {}를 추가하게 만드는 링커 문제가 발생했습니다 (상황을 기억하지 않습니다). 나는 더 잘 알고 있습니다. :-)


음, 이것은 :

private:
    MyClass(const MyClass&) {}
    MyClass& operator=(const MyClass&) {}

여전히 기술적 MyClass으로 회원과 친구가 복사 수 있습니다. 물론 이러한 유형과 함수는 이론적으로 사용자가 제어 할 수 있지만 클래스는 여전히 복사 가능 합니다. 최소한 boost::noncopyable및을 사용 = delete하면 아무도 클래스를 복사 할 수 없습니다 .


일부 사람들이 C ++ 11에서 클래스를 복사 불가능하게 만드는 것이 더 쉽다고 주장하는 이유를 모르겠습니다.

"더 쉽게 소화 할 수있는"만큼 "쉬운"것이 아닙니다.

이걸 고려하세요:

class MyClass
{
private:
    MyClass(const MyClass&) {}
    MyClass& operator=(const MyClass&) {}
};

C ++에 대한 소개 텍스트를 읽었지만 관용적 C ++ (예 : 많은 C ++ 프로그래머)에 거의 노출되지 않은 C ++ 프로그래머라면 이것은 ... 혼란 스럽습니다. 복사 생성자와 복사 할당 연산자를 선언하지만 비어 있습니다. 그렇다면 왜 그들을 선언합니까? 예, private하지만 더 많은 질문을 제기 할뿐입니다 . 왜 비공개로 만들까요?

이것이 복사를 방지하는 이유를 이해하려면 비공개로 선언함으로써 비회원 / 친구가 복사 할 수 없도록 만드는 것임을 깨달아야합니다. 이것은 초보자에게 즉각적으로 분명하지 않습니다. 복사를 시도 할 때 표시되는 오류 메시지도 아닙니다.

이제 C ++ 11 버전과 비교합니다.

class MyClass
{
public:
    MyClass(const MyClass&) = delete;
    MyClass& operator=(const MyClass&) = delete;
};

이 클래스를 복사 할 수 없다는 것을 이해하려면 무엇이 필요합니까? = delete구문의 의미를 이해하는 것 이상은 없습니다 . C ++ 11의 구문 규칙을 설명하는 책은 정확히 무엇을하는지 알려줄 것입니다. 이 코드의 효과는 경험이없는 C ++ 사용자에게 분명합니다.

이 관용구의 대단한 점은 그것이 당신이 의미하는 바를 정확히 말할 수있는 가장 명확하고 명백한 방법이기 때문에 관용구가된다는 것입니다.

심지어 boost::noncopyable조금 더 생각이 필요합니다. 예, "복사 불가능"이라고하므로 자체 문서화입니다. 그러나 전에 본 적이 없다면 의문이 제기됩니다. 복사 할 수없는 것에서 파생되는 이유는 무엇입니까? 오류 메시지가 boost::noncopyable의 복사 생성자 에 대해 말하는 이유는 무엇 입니까? 다시 말하지만, 관용구를 이해하려면 더 많은 정신적 노력이 필요합니다.


첫 번째는 다른 사람들이 지적했듯이 관용구를 잘못 이해 하고 비공개로 선언 하고 정의 하지 않는다는 것입니다 .

class noncopyable {
   noncopyable( noncopyable const & );
   noncopyable& operator=( noncopyable const & );
};

의 반환 유형은 operator=기본적으로 무엇이든 될 수 있습니다. 이 시점에서 헤더에서 해당 코드를 읽으면 실제로 무엇을 의미합니까? 친구 만 복사 할 수 있습니까? 아니면 복사 할 수 없습니까? 예에서와 같이 정의를 제공 하면 클래스 내부에서만 복사 할 수 있으며 친구에 의해서만 복사 될 수 있다는 의미 이며이를 I cannot be copy 으로 변환하는 것은 정의가 부족하기 때문입니다 . 그러나 헤더에 정의가 없다는 것은 cpp 파일에서 정의 할 수 있기 때문에 모든 곳 에서 정의가 부족한 것과 동의어가 아닙니다 .

This is where inheriting from a type called noncopyable makes it explicit that the intention is to avoid copies, in the same way that if you manually wrote the code above you should document with a comment in the line that the intention is disabling copies.

C++11 does not change any of this, it just makes the documentation explicit in the code. In the same line that you declare the copy constructor as deleted you are documented that you want it fully disabled.

As a last comment, the feature in C++11 is not just about being able to write noncopyable with less code or better, but rather about inhibiting the compiler from generating code that you don't want generated. This is just one use of that feature.


In addition to the points others have brought up...

Having a private copy constructor and copy assignment operator that you do not define prevents anyone from making copies. However, if a member function or friend function attempts to make a copy, they will receive a link-time error. If they attempt to do so where you have explicitly deleted those functions, they will receive a compile-time error.

I always make my errors occur as soon as possible. Make run-time errors happen at the point of error instead of later on (so make the error happen when you change the variable instead of when you read it). Make all run-time errors into link-time errors so the code never has a chance to be wrong. Make all link-time errors into compile-time errors to speed up development and have slightly more useful error messages.


It's more readable and allows the compiler to give better errors.

The 'deleted' is more clear to a reader, especially if they're skimming over the class. Likewise, the compiler can tell you that you're trying to copy a non-copyable type, instead of giving you a generic 'trying to access private member' error.

But really, it's just a convenience feature.


People here are recommending that you declare member functions without defining them. I would like to point out that such an approach isn't portable. Some compilers/linkers require that if you declare a member function then you must also define it, even if it isn't used. If you are using only VC++, GCC, clang then you can get away with this, but if you are trying to write truly portable code then some other compilers (e.g. Green Hills) will fail.

참고URL : https://stackoverflow.com/questions/9458741/with-explicitly-deleted-member-functions-in-c11-is-it-still-worthwhile-to-inh

반응형