函数声明后=删除的含义

时间:2011-04-01 13:14:31

标签: c++ function c++11 declaration delete-operator

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

= delete在这种情况下的含义是什么?

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

9 个答案:

答案 0 :(得分:177)

删除功能是a C++11 feature

  

现在可以表达“禁止复制”的常用习语   直接:

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

答案 1 :(得分:75)

  1. = 0表示函数是纯虚函数,您无法从此类实例化对象。您需要从中派生并实现此方法
  2. = delete表示编译器不会为您生成这些构造函数。 AFAIK只允许复制构造函数和赋值运算符。但我对即将推出的标准不太满意。

答案 2 :(得分:17)

摘自 C ++编程语言[第4版] - Bjarne Stroustrup 一书,讨论了使用=delete背后的真实目的

  

通常使用层次结构中的类的默认副本或移动   灾难:只给出指向基地的指针,我们根本不知道是什么   派生类的成员有(§3.2.2),所以我们不知道如何复制   它们。因此,最好的办法是删除默认副本   并移动操作,即消除默认定义   这两个行动:

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机制是通用的,也就是说,它可以用来抑制任何操作

答案 3 :(得分:7)

  

还有其他"修饰符" ($('button[name="postname"]').click(function(e){ e.preventDefault(); // add this ......... }); = 0除外)?

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

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

答案 4 :(得分:3)

= delete是C ++ 11中引入的一个功能。根据{{​​1}},不允许调用该函数。

详细说明。

假设在课堂上。

=delete

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

答案 5 :(得分:3)

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

//  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个中的任何一个,你只需注释掉相应的行。

示例:类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)

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

您还可以使用' =删除'禁止不同大小的值的隐式促销......例如

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

答案 6 :(得分:2)

新的C ++ 0x标准。请参阅N3242 working draft

中的第8.4.3节

答案 7 :(得分:0)

这是C ++ 0x标准中的新功能,您可以删除继承的函数。

答案 8 :(得分:0)

已删除的函数隐式内联

(现有答案的附录)

...并且已删除的函数应是该函数的第一个声明(删除函数模板的显式特化除外-删除应在该特化的第一个声明处),这意味着您无法声明一个函数并随后将其删除例如,在翻译单位本地定义。

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

  

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

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

最终示例

具有删除的定义的主要功能模板可以专门化

尽管一般的经验法则是to avoid specializing function templates,因为专业化不参与重载解析的第一步,但是在某些情况下,可以使用它是有用的。例如。当使用一个没有定义的 non-overloaded 主函数模板来匹配所有不希望隐式转换为转换匹配重载的所有类型时;即通过仅在未定义,未重载的主函数模板的显式专业化中实现完全类型匹配来隐式删除许多隐式转换匹配。

在删除C ++ 11的函数概念之前,可以通过简单地省略主要函数模板的定义来做到这一点,但这却产生了模糊的 undefined reference 错误,可以说没有任何语义意图来自主要功能模板的作者(故意省略?)。如果我们改为显式删除主功能模板,则在找不到合适的显式专业化的情况下出现的错误消息会变得更好,并且还表明有意省略/删除主功能模板的定义。

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

但是,除了简单地省略上面的主要功能模板的定义之外,当没有明确的专业化匹配时会产生模糊的未定义参考错误,而是可以删除主要模板定义:

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