C++ 函数声明后=delete的含义

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5513881/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 18:20:56  来源:igfitidea点击:

Meaning of = delete after function declaration

c++functionc++11declarationdelete-operator

提问by Pat O'Keefe

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

What does = deletemean in that context?

= delete在这种情况下是什么意思?

Are there any other "modifiers" (other than = 0and = delete)?

是否还有其他“修饰符”(除了= 0= delete)?

采纳答案by Prasoon Saurav

Deleting a function is a C++11 feature:

删除函数是C++11 的一个特性

The common idiom of "prohibiting copying" can now be expressed directly:

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

[...]

The "delete" mechanism can be used for any function. For example, we can eliminate an undesired conversion like this:

struct Z {
    // ...

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

“禁止复制”这个常见的成语现在可以直接表达了:

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
};

回答by mkaes

  1. = 0means that a function is pure virtual and you cannot instantiate an object from this class. You need to derive from it and implement this method
  2. = deletemeans that the compiler will not generate those constructors for you. AFAIK this is only allowed on copy constructor and assignment operator. But I am not too good at the upcoming standard.
  1. = 0意味着一个函数是纯虚拟的,你不能从这个类实例化一个对象。您需要从中派生并实现此方法
  2. = delete意味着编译器不会为您生成这些构造函数。AFAIK 这仅适用于复制构造函数和赋值运算符。但我不太擅长即将到来的标准。

回答by Saurav Sahu

This excerpt from The C++ Programming Language [4th Edition] - Bjarne Stroustrupbook talks about the real purposebehind using =delete:

摘自The C++ Programming Language [第 4 版] - Bjarne Stroustrup书谈到了使用背后的真正目的=delete

3.3.4 Suppressing Operations

Using the default copy or move for a class in a hierarchy is typically a disaster: given only a pointer to a base, we simply don't know what members the derived class has, so we can't know how to copy them. So, the best thing to do is usually to delete the default copy and move operations, that is, to eliminate the default definitions of those two operations:

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();
    // ...
};

Now an attempt to copy a Shape will be caught by the compiler.

The =deletemechanism is general, that is, it can be used to suppress any operation

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();
    // ...
};

现在,编译器将捕获复制 Shape 的尝试。

=delete机制是通用的,也就是说,它可以被用来抑制任何操作

回答by Kyle Delaney

Are there any other "modifiers" (other than = 0and = delete)?

是否还有其他“修饰符”(除了= 0= delete)?

Since it appears no one else answered this question, I should mention that there is also =default.

由于似乎没有其他人回答这个问题,我应该提到还有=default.

https://docs.microsoft.com/en-us/cpp/cpp/explicitly-defaulted-and-deleted-functions#explicitly-defaulted-functions

https://docs.microsoft.com/en-us/cpp/cpp/explicitly-defaulted-and-deleted-functions#explicitly-defaulted-functions

回答by 2785528

The coding standards I've worked with have had the following for most of class declarations.

我使用过的编码标准对于大多数类声明都有以下​​内容。

//  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)

If you use any of these 6, you simply comment out the corresponding line.

如果您使用这 6 个中的任何一个,您只需注释掉相应的行。

Example: class FizzBus require only dtor, and thus do not use the other 5.

示例:类 FizzBu​​s 只需要 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)

We comment out only 1 here, and install the implementation of it else where (probably where the coding standard suggests). The other 5 (of 6) are disallowed with delete.

我们在这里只注释掉 1,并在其他地方(可能是编码标准建议的地方)安装它的实现。其他 5 个(共 6 个)不允许删除。

You can also use '= delete' to disallow implicit promotions of different sized values ... example

您还可以使用 '= 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;

回答by ashutosh

= deleteis a feature introduce in C++11. As per =deleteit will not allowed to call that function.

= delete是 C++11 中引入的一个特性。根据=delete它不允许调用该函数。

In detail.

详细。

Suppose in a class.

假设在一个班级。

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

  }
};

While calling this function for obj assignment it will not allowed. Means assignment operator is going to restrict to copy from one object to another.

在为 obj 赋值调用此函数时,它是不允许的。意味着赋值运算符将限制从一个对象复制到另一个对象。

回答by dubnde

New C++0x standard. Please see section 8.4.3 in the N3242 working draft

新的 C++0x 标准。请参见N3242工作草案中的8.4.3节

回答by dfri

A deleted function is implicitly inline

被删除的函数是隐式内联的

(Addendum to existing answers)

(现有答案的附录)

... And a deleted function shall be the first declaration of the function (except for deleting explicit specializations of function templates - deletion should be at the first declaration of the specialization), meaning you cannot declare a function and later delete it, say, at its definition local to a translation unit.

...并且删除的函数应该是函数的第一个声明(除了删除函数模板的显式特化 - 删除应该在特化的第一个声明处),这意味着您不能声明一个函数然后再删除它,例如,在翻译单元的本地定义。

Citing [dcl.fct.def.delete]/4:

引用[dcl.fct.def.delete]/4

A deleted function is implicitly inline. ( Note:The one-definition rule ([basic.def.odr]) applies to deleted definitions. — end note] A deleted definition of a function shall be the first declaration of the function or, for an explicit specialization of a function template, the first declaration of that specialization. [ Example:

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

end example)

删除的函数是隐式内联的。(注意:单一定义规则([basic.def.odr])适用于已删除的定义。—尾注] 删除的函数定义应是函数的第一个声明,或者对于函数模板的显式特化, 该专业化的第一个声明。[ 示例:

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

-结束示例

A primary function template with a deleted definitioncan be specialized

具有删除定义的主函数模板可以特化

Albeit a general rule of thumb is to avoid specializing function templatesas specializations do not participate in the first step of overload resolution, there are arguable some contexts where it can be useful. E.g. when using a non-overloadedprimary function template with no definition to match all types which one would not like implicitly converted to an otherwise matching-by-conversion overload; i.e., to implicitly remove a number of implicit-conversion matches by only implementing exact type matches in the explicit specialization of the non-defined, non-overloaded primary function template.

尽管一般的经验法则是避免特化函数模板,因为特化不参与重载解析的第一步,但有争议的一些上下文可能有用。例如,当使用没有定义的非重载主函数模板来匹配所有类型时,人们不喜欢隐式转换为按转换匹配的重载;即,通过仅在未定义、未重载的主函数模板的显式特化中实现精确类型匹配来隐式删除多个隐式转换匹配。

Before the deleted function concept of C++11, one could do this by simply omitting the definition of the primary function template, but this gave obscure undefined referenceerrors that arguably gave no semantic intent whatsoever from the author of primary function template (intentionally omitted?). If we instead explicitly delete the primary function template, the error messages in case no suitable explicit specialization is found becomes much nicer, and also shows that the omission/deletion of the primary function template's definition was intentional.

在 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< ...
}

However, instead of simply omitting a definition for the primary function template above, yielding an obscure undefined reference error when no explicit specialization matches, the primary template definition can be deleted:

然而,当没有显式特化匹配时,不是简单地省略主函数模板的定义,产生一个模糊的未定义引用错误,主模板定义可以被删除:

#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; */
}

Yielding a more more readable error message, where the deletion intent is also clearly visible (where an undefined referenceerror could lead to the developer thinking this an unthoughtful mistake).

产生更易读的错误消息,其中删除意图也清晰可见(未定义的引用错误可能导致开发人员认为这是一个不经意的错误)。

Returning to why would we ever want to use this technique? Again, explicit specializations could be useful to implicitlyremove implicit conversions.

回到为什么我们要使用这种技术?同样,显式特化对于隐式删除隐式转换可能很有用。

#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; */
}

回答by Tayyab

This is new thing in C++ 0x standards where you can delete an inherited function.

这是 C++ 0x 标准中的新事物,您可以在其中删除继承的函数。