函数声明后 = delete 的含义

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

在这种情况下,= delete意味着什么?

除了 = 0= delete之外,还有其他的“修饰语”吗?

153488 次浏览

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

“禁止复制”的常用成语;现在可以表达 直接:< / p >

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

[…]

< p >“delete"机构可以用于任何功能。例如,我们

struct Z {
// ...


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

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

  1. = 0意味着一个函数是纯虚的,你不能从这个类实例化一个对象。您需要从中派生并实现此方法
  2. = delete意味着编译器不会为你生成这些构造函数。AFAIK,这只允许在复制构造函数和赋值操作符上。但我不太擅长即将到来的标准。

新的c++ 0x标准。请参见N3242工作草案 . xml文件中的8.4.3节

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

在细节。

假设在一个类中。

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


}
};

当调用这个函数进行obj赋值时,它将不被允许。表示赋值操作符将限制从一个对象复制到另一个对象。

这段摘录自c++编程语言[第四版]- Bjarne Stroustrup书,讲述了使用=delete背后的真正目的:

3.3.4抑制操作

对层次结构中的类使用默认的复制或移动 a 灾难:只给出一个指向基数的指针,我们根本不知道是什么 派生类的成员,因此我们不能知道如何复制 < / em >。所以,最好的办法通常是删除默认副本 而移动操作,即消除默认的定义 这两个操作:

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

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

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

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

我使用过的编码标准对大多数类声明都有如下规定。

//  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个中的5个)是不允许使用delete的。

你也可以使用'= 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;

删除的函数隐式内联

(现有答案的补充)

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

援引(dcl.fct.def.delete) / 4:

删除的函数隐式内联。注意:一个定义 规则 ((basic.def.odr)) 适用于已删除的定义。- 最后请注意]删除的定义 函数的第一个声明应为函数或for 第一个是函数模板的显式特化 专门化的声明。(例子:< / p >

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

- __abc0)

带有删除定义的主函数模板可以被特殊化

尽管一般的经验法则是避免函数模板专门化,因为专门化不参与重载解析的第一步,但在某些情况下,它可能是有用的。例如,当使用没有定义的non-overloaded主函数模板来匹配所有不希望隐式转换为其他转换匹配重载的类型时;也就是说,只在非定义的、非重载的主函数模板的显式特化中实现精确的类型匹配,从而隐式地删除一些隐式转换匹配。

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

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

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

一个小例子总结一些常见的用法:

class MyClass
{
public:
// Delete copy constructor:
// delete the copy constructor so you cannot copy-construct an object
// of this class from a different object of this class
MyClass(const MyClass&) = delete;


// Delete assignment operator:
// delete the `=` operator (`operator=()` class method) to disable copying
// an object of this class
MyClass& operator=(const MyClass&) = delete;


// Delete constructor with certain types you'd like to
// disallow:
// (Arbitrary example) don't allow constructing from an `int` type. Expect
// `uint64_t` instead.
MyClass(uint64_t);
MyClass(int) = delete;


// "Pure virtual" function:
// `= 0` makes this is a "pure virtual" method which *must* be overridden
// by a child class
uint32_t getVal() = 0;
}

待办事项:

  1. 我仍然需要做一个更彻底的例子,并运行它来显示一些用法和输出,以及它们对应的错误消息。

另请参阅

  1. https://www.stroustrup.com/C++11FAQ.html#default - section "默认值控制:defaultdelete"