Pat*_*efe 224 c++ declaration function delete-operator c++11
class my_class
{
...
my_class(my_class const &) = delete;
...
};
Run Code Online (Sandbox Code Playgroud)
= delete在这种情况下意味着什么?
还有其他"修饰符"(除了= 0和= delete)吗?
Pra*_*rav 187
删除函数是C++ 11的一项功能:
现在可以直接表达"禁止复制"的常用习语:
Run Code Online (Sandbox Code Playgroud)class X { // ... X& operator=(const X&) = delete; // Disallow copying X(const X&) = delete; };[...]
"删除"机制可用于任何功能.例如,我们可以消除不需要的转换,如下所示:
Run Code Online (Sandbox Code Playgroud)struct Z { // ... Z(long long); // can initialize with an long long Z(long) = delete; // but not anything less };
mka*_*aes 77
= 0表示函数是纯虚拟的,您无法从此类实例化对象.您需要从中派生并实现此方法= delete意味着编译器不会为您生成这些构造函数.AFAIK只允许复制构造函数和赋值运算符.但我对即将推出的标准不太了解.Sau*_*ahu 24
摘自"C++编程语言[第4版] - Bjarne Stroustrup"一书讲述了使用背后的真正目的=delete:
使用层次结构中的类的默认副本或移动通常是一个灾难:只给出指向基类的指针,我们根本不知道派生类有哪些成员(§3.2.2),所以我们无法知道如何复制它们.因此,最好的做法通常是删除默认副本和移动操作,即消除这两个操作的默认定义:
Run Code Online (Sandbox Code Playgroud)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.
我使用过的编码标准对于大多数类声明都有以下内容。
// 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)
Run Code Online (Sandbox Code Playgroud)
如果您使用这 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)
Run Code Online (Sandbox Code Playgroud)
我们在这里只注释掉 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;
Run Code Online (Sandbox Code Playgroud)
(现有答案的附录)
\n\n...并且删除的函数应是该函数的第一个声明(除了删除函数模板的显式特化 - 删除应该在特化的第一个声明处),这意味着您不能声明一个函数然后再删除它,比如说,在翻译单元本地的定义中。
\n\n\n\n\n\n\n删除的函数是隐式内联的。(注:单一定义规则 ( [basic.def.odr] )\n 适用于已删除的定义。 \xe2\x80\x94尾注] 函数的已删除定义应为第一个声明函数的\n 或对于函数模板的显式特化,该特化的第一个\n 声明。[ 示例:
\n\nRun Code Online (Sandbox Code Playgroud)\n\nstruct sometype {\n sometype();\n};\nsometype::sometype() = delete; // ill-formed; not first declaration\n\xe2\x80\x94结束示例)
\n
尽管一般的经验法则是避免专门化函数模板,因为专门化不参与重载决策的第一步,但在某些情况下它可能有用,这是有争议的。例如,当使用没有定义的非重载主函数模板来匹配所有不希望隐式转换为其他匹配转换重载的类型时;即,通过仅在未定义、非重载的主函数模板的显式特化中实现精确类型匹配来隐式删除许多隐式转换匹配。
\n\n在 C++11 删除函数概念之前,人们可以通过简单地省略主函数模板的定义来做到这一点,但这会产生模糊的未定义引用错误,可以说,主函数模板的作者没有给出任何语义意图(故意省略) ?)。如果我们显式删除主函数模板,则在找不到合适的显式专业化的情况下的错误消息会变得更好,并且还表明主函数模板定义的省略/删除是故意的。
\n\n#include <iostream>\n#include <string>\n\ntemplate< typename T >\nvoid use_only_explicit_specializations(T t);\n\ntemplate<>\nvoid use_only_explicit_specializations<int>(int t) {\n std::cout << "int: " << t;\n}\n\nint main()\n{\n const int num = 42;\n const std::string str = "foo";\n use_only_explicit_specializations(num); // int: 42\n //use_only_explicit_specializations(str); // undefined reference to `void use_only_explicit_specializations< ...\n}\nRun Code Online (Sandbox Code Playgroud)\n\n然而,不是简单地省略上面主函数模板的定义,当没有显式专业化匹配时产生模糊的未定义引用错误,而是可以删除主模板定义:
\n\n#include <iostream>\n#include <string>\n\ntemplate< typename T >\nvoid use_only_explicit_specializations(T t) = delete;\n\ntemplate<>\nvoid use_only_explicit_specializations<int>(int t) {\n std::cout << "int: " << t;\n}\n\nint main()\n{\n const int num = 42;\n const std::string str = "foo";\n use_only_explicit_specializations(num); // int: 42\n use_only_explicit_specializations(str);\n /* error: call to deleted function \'use_only_explicit_specializations\' \n note: candidate function [with T = std::__1::basic_string<char>] has \n been explicitly deleted\n void use_only_explicit_specializations(T t) = delete; */\n}\nRun Code Online (Sandbox Code Playgroud)\n\n产生更具可读性的错误消息,其中删除意图也清晰可见(其中未定义的引用错误可能导致开发人员认为这是一个不经深思熟虑的错误)。
\n\n回到我们为什么要使用这种技术?同样,显式专业化对于隐式删除隐式转换可能很有用。
\n\n#include <cstdint>\n#include <iostream>\n\nvoid warning_at_best(int8_t num) { \n std::cout << "I better use -Werror and -pedantic... " << +num << "\\n";\n}\n\ntemplate< typename T >\nvoid only_for_signed(T t) = delete;\n\ntemplate<>\nvoid only_for_signed<int8_t>(int8_t t) {\n std::cout << "UB safe! 1 byte, " << +t << "\\n";\n}\n\ntemplate<>\nvoid only_for_signed<int16_t>(int16_t t) {\n std::cout << "UB safe! 2 bytes, " << +t << "\\n";\n}\n\nint main()\n{\n const int8_t a = 42;\n const uint8_t b = 255U;\n const int16_t c = 255;\n const float d = 200.F;\n\n warning_at_best(a); // 42\n warning_at_best(b); // implementation-defined behaviour, no diagnostic required\n warning_at_best(c); // narrowing, -Wconstant-conversion warning\n warning_at_best(d); // undefined behaviour!\n\n only_for_signed(a);\n only_for_signed(c);\n\n //only_for_signed(b); \n /* error: call to deleted function \'only_for_signed\' \n note: candidate function [with T = unsigned char] \n has been explicitly deleted\n void only_for_signed(T t) = delete; */\n\n //only_for_signed(d);\n /* error: call to deleted function \'only_for_signed\' \n note: candidate function [with T = float] \n has been explicitly deleted\n void only_for_signed(T t) = delete; */\n}\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
98067 次 |
| 最近记录: |