의미 = 함수 선언 후 삭제


242
class my_class
{
    ...
    my_class(my_class const &) = delete;
    ...
};

= delete그 맥락에서 무엇을 의미합니까?

다른 "수정 자"( = 0및 이외 = delete)가 있습니까?


23
@Blindy C ++ 0x에서 곧 표준이 될 것입니다.
Konrad Rudolph

1
나는이 C ++ 0x 기능을 놓쳤습니다. 나는 그것이 #define0으로 평가 된 다음 숨겨진 함수 또는 무언가를 선언 한 la Qt 라고 생각했습니다 .
Blindy

나는 동일하거나 비슷한 것을 의미하는 '비활성화'키워드를 회상했습니다. 상상하고 있습니까? 아니면 그들 사이에 미묘한 차이가 있습니까?
Stewart

답변:


201

함수 삭제는 C ++ 11 기능입니다 .

"복사 금지"의 일반적인 관용구를 이제 직접 표현할 수 있습니다.

class X {
    // ...
    X& operator=(const X&) = delete;  // Disallow copying
    X(const X&) = delete;
};

[...]

"삭제"메커니즘은 모든 기능에 사용할 수 있습니다. 예를 들어 다음과 같이 원하지 않는 변환을 제거 할 수 있습니다.

struct Z {
    // ...

    Z(long long);     // can initialize with an long long         
    Z(long) = delete; // but not anything less
};

3
copy-ctor와 operator = "private"을 만드는 것만으로 "복사 금지"방법이 아닙니까? 이것은 조금 더 나아가 컴파일러에게 함수를 생성하지 않도록 지시합니다. 개인 및 = 삭제 인 경우 이중 복사가 금지됩니까?
Reb. Cabin

8
@Reb =delete는 메소드를 볼 수있는 컨텍스트 private(예 : 클래스와 친구 내) 에서도 메소드에 액세스 할 수 없게 합니다. 코드를 읽을 때 불확실성을 제거합니다. @Prasoon, 두 번째 예는 여전히 생성자를 삭제하는 것 operator long ()입니다. 예를 들어 삭제 된 것을 보는 것이 좋습니다 .
Toby Speight

2
@ Reb.Cabin 사용은 = delete더 나은 사용하는 것보다 private일반적으로이 때문에 또는 다른 유사한 메커니즘 원하는 금지 된 기능이 눈에 띄게 선언 및 오버로드 확인 등을 위해 고려되어야하는 것이 가능한 한 빨리 실패하고 사용자에게 명확한 오류를 제공 할 수 있도록. 선언을 "숨김"과 관련된 솔루션은이 효과를 줄입니다.
Leushenko

1
복사 생성자를 공개하고 삭제 키워드를 적용해야하는 특별한 이유가 있습니까? 왜 생성자를 비공개로두고 키워드를 적용하지 않습니까?
Dohn Joe

81
  1. = 0함수가 순수 가상이고이 클래스에서 객체를 인스턴스화 할 수 없음을 의미합니다. 그것에서 파생 되어이 방법을 구현해야합니다
  2. = delete컴파일러가 생성자를 생성하지 않음을 의미합니다. AFAIK 이것은 복사 생성자 및 할당 연산자에서만 허용됩니다. 그러나 나는 다가오는 표준에 너무 좋지 않다.

4
=delete구문 의 다른 용도가 있습니다. 예를 들어, 호출로 발생할 수있는 암시 적 변환을 명시 적으로 허용하지 않을 때 사용할 수 있습니다. 이를 위해 오버로드 된 기능을 삭제하십시오. 자세한 정보는 C ++ 0x의 Wikipedia 페이지를 참조하십시오.
LiKao

내가 찾 자마자 그렇게 할 것입니다. c ++ 0X를 따라 잡을
때가 됐습니다

예, C ++ 0x는 바위입니다. GCC 4.5+가 더 일반적 일 때까지 기다릴 수 없으므로 람다 사용을 시작할 수 있습니다.
LiKao

5
에 대한 설명 = delete이 완전히 정확하지 않습니다. = delete모든 함수에 사용할 수 있으며,이 경우 명시 적으로 삭제 된 것으로 표시되고 사용하면 컴파일러 오류가 발생합니다. 특수 멤버 함수의 경우 이는 특히 컴파일러에서 생성하지 않지만 = delete실제로는 삭제되지 않은 결과 일뿐 입니다.
MicroVirus

28

The C ++ Programming Language [4th Edition]-Bjarne Stroustrup의 발췌문은 다음을 사용 하는 실제 목적 에 대해 이야기합니다 =delete.

3.3.4 작동 억제

계층 구조에서 클래스에 대한 기본 복사 또는 이동을 사용하는 것은 일반적으로 재난입니다 . 기본에 대한 포인터 만 제공하면 파생 클래스의 멤버를 모를 뿐이므로 복사 방법을 알 수 없습니다 . 따라서 가장 좋은 방법은 일반적으로 기본 복사 및 이동 작업을 삭제하는 것, 즉이 두 작업의 기본 정의를 제거하는 것입니다.

class Shape {
public:
  Shape(const Shape&) =delete; // no copy operations
  Shape& operator=(const Shape&) =delete;

  Shape(Shape&&) =delete; // no move operations
  Shape& operator=(Shape&&) =delete;
  ˜Shape();
    // ...
};

이제 셰이프를 복사하려는 시도가 컴파일러에 의해 포착됩니다.

=delete메커니즘은 어떤 동작을 억제하기 위해 사용될 수있는, 즉 일반적이며



5

내가 작업 한 코딩 표준에는 대부분의 클래스 선언에 대해 다음과 같은 내용이 있습니다.

//  coding standard: disallow when not used
T(void)                  = delete; // default ctor    (1)
~T(void)                 = delete; // default dtor    (2)
T(const T&)              = delete; // copy ctor       (3)
T(const T&&)             = delete; // move ctor       (4)
T& operator= (const T&)  = delete; // copy assignment (5)
T& operator= (const T&&) = delete; // move assignment (6)

이 6 개 중 하나를 사용하면 해당 라인을 주석 처리하면됩니다.

예 : FizzBus 클래스는 dtor 만 필요하므로 다른 5 개는 사용하지 마십시오.

//  coding standard: disallow when not used
FizzBuzz(void)                         = delete; // default ctor (1)
// ~FizzBuzz(void);                              // dtor         (2)
FizzBuzz(const FizzBuzz&)              = delete; // copy ctor    (3)
FizzBuzz& operator= (const FizzBuzz&)  = delete; // copy assig   (4)
FizzBuzz(const FizzBuzz&&)             = delete; // move ctor    (5)
FizzBuzz& operator= (const FizzBuzz&&) = delete; // move assign  (6)

여기서는 1 개만 주석 처리하고 다른 곳에 구현을 설치하십시오 (아마도 코딩 표준이 제안하는 위치). 나머지 5 개 중 6 개는 삭제가 허용되지 않습니다.

'= delete'를 사용하여 다른 크기 값의 암시 적 승격을 허용하지 않을 수도 있습니다 ... 예

// disallow implicit promotions 
template <class T> operator T(void)              = delete;
template <class T> Vuint64& operator=  (const T) = delete;
template <class T> Vuint64& operator|= (const T) = delete;
template <class T> Vuint64& operator&= (const T) = delete;

3

= deleteC ++ 11의 기능 소개입니다. =delete그에 따라 해당 함수를 호출 할 수 없습니다.

상세히.

수업에서 가정 해 봅시다.

Class ABC{
 Int d;
 Public:
  ABC& operator= (const ABC& obj) =delete
  {

  }
};

obj 할당을 위해이 함수를 호출하는 동안에는 허용되지 않습니다. 할당 연산자가 한 객체에서 다른 객체로 복사를 제한한다는 의미입니다.



1

삭제 된 함수는 암시 적으로 인라인입니다.

(기존 답변에 대한 부록)

... 그리고 삭제 된 함수는 함수의 첫 번째 선언이어야합니다 (함수 템플릿의 명시 적 전문화를 삭제하는 것을 제외하고-삭제는 전문화의 첫 번째 선언에 있어야 함). 함수를 선언하고 나중에 삭제할 수 없음을 의미합니다. 정의에 따라 번역 단위에 국한됩니다.

인용 [dcl.fct.def.delete] / 4 :

삭제 된 함수는 암시 적으로 인라인입니다. ( 참고 : 1- 정의 규칙 ( [basic.def.odr] )은 삭제 된 정의에 적용됩니다. — 끝 주 ] 함수의 삭제 된 정의는 함수의 첫 번째 선언이거나 함수 템플릿의 명시 적 전문화 여야합니다. , 해당 전문화의 첫 번째 선언 [예 :

struct sometype {
  sometype();
};
sometype::sometype() = delete;      // ill-formed; not first declaration

최종 예 )

정의 가 삭제 된 기본 함수 템플릿을 특수화 할 수 있습니다.

일반적 으로 전문화는 과부하 해결의 첫 번째 단계에 참여하지 않기 때문에 기능 템플릿 특수화를 피하는 것이지만 유용한 컨텍스트가 있습니다. 예를 들어, 정의가없는 오버로드되지 않은 기본 함수 템플릿을 사용하여 변환과 일치하는 오버로드로 암시 적으로 변환되지 않는 모든 유형과 일치하는 경우 즉, 정의되지 않은 오버로드되지 않은 기본 함수 템플릿의 명시적인 특수화에서 정확한 형식 일치 만 구현하여 여러 개의 암시 적 변환 일치를 암시 적으로 제거합니다.

C ++ 11의 삭제 된 함수 개념 이전에는 기본 함수 템플릿의 정의를 생략하여이를 수행 할 수 있었지만 기본 함수 템플릿 작성자의 의미 론적 의도가 전혀 없었던 정의되지 않은 참조 오류가 발생했습니다 (의도적으로 생략되었습니다) ?). 대신 기본 함수 템플릿을 명시 적으로 삭제하면 적절한 명시 적 전문화를 찾을 수없는 경우의 오류 메시지가 훨씬 더 좋아지고 기본 함수 템플릿 정의의 생략 / 삭제가 의도적 인 것임을 나타냅니다.

#include <iostream>
#include <string>

template< typename T >
void use_only_explicit_specializations(T t);

template<>
void use_only_explicit_specializations<int>(int t) {
    std::cout << "int: " << t;
}

int main()
{
    const int num = 42;
    const std::string str = "foo";
    use_only_explicit_specializations(num);  // int: 42
    //use_only_explicit_specializations(str); // undefined reference to `void use_only_explicit_specializations< ...
}

그러나 위의 1 차 함수 템플리트에 대한 정의를 생략하고 명시적인 특수화와 일치하지 않는 경우 불명확 한 참조 오류가 발생하는 대신 1 차 템플리트 정의를 삭제할 수 있습니다.

#include <iostream>
#include <string>

template< typename T >
void use_only_explicit_specializations(T t) = delete;

template<>
void use_only_explicit_specializations<int>(int t) {
    std::cout << "int: " << t;
}

int main()
{
    const int num = 42;
    const std::string str = "foo";
    use_only_explicit_specializations(num);  // int: 42
    use_only_explicit_specializations(str);
    /* error: call to deleted function 'use_only_explicit_specializations' 
       note: candidate function [with T = std::__1::basic_string<char>] has 
       been explicitly deleted
       void use_only_explicit_specializations(T t) = delete; */
}

삭제 의도도 명확하게 보이는 더 읽기 쉬운 오류 메시지를 생성합니다 ( 정의되지 않은 참조 오류로 인해 개발자가이를 생각하지 못한 실수로 생각할 수 있음).

왜이 기술을 사용하고 싶습니까? 또, 명시 적 특수화는 것이 유용 할 수 암묵적으로 암시 적 변환을 제거합니다.

#include <cstdint>
#include <iostream>

void warning_at_best(int8_t num) { 
    std::cout << "I better use -Werror and -pedantic... " << +num << "\n";
}

template< typename T >
void only_for_signed(T t) = delete;

template<>
void only_for_signed<int8_t>(int8_t t) {
    std::cout << "UB safe! 1 byte, " << +t << "\n";
}

template<>
void only_for_signed<int16_t>(int16_t t) {
    std::cout << "UB safe! 2 bytes, " << +t << "\n";
}

int main()
{
    const int8_t a = 42;
    const uint8_t b = 255U;
    const int16_t c = 255;
    const float d = 200.F;

    warning_at_best(a); // 42
    warning_at_best(b); // implementation-defined behaviour, no diagnostic required
    warning_at_best(c); // narrowing, -Wconstant-conversion warning
    warning_at_best(d); // undefined behaviour!

    only_for_signed(a);
    only_for_signed(c);

    //only_for_signed(b);  
    /* error: call to deleted function 'only_for_signed' 
       note: candidate function [with T = unsigned char] 
             has been explicitly deleted
       void only_for_signed(T t) = delete; */

    //only_for_signed(d);
    /* error: call to deleted function 'only_for_signed' 
       note: candidate function [with T = float] 
             has been explicitly deleted
       void only_for_signed(T t) = delete; */
}

0

상속 된 함수를 삭제할 수있는 C ++ 0x 표준의 새로운 기능입니다.


11
모든 기능을 삭제할 수 있습니다. 예를 들어 void foo(int); template <class T> void foo(T) = delete;모든 암시 적 변환을 중지합니다. int유형의 인수 만 허용되며 다른 모든 인수는 "삭제 된"기능을 인스턴스화하려고 시도합니다.
UncleBens
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.