class my_class
{
...
my_class(my_class const &) = delete;
...
};
在这个上下文中,= delete
是什么意思?
除了 = 0
和 = delete
之外,还有其他的“修饰符”吗?
class my_class
{
...
my_class(my_class const &) = delete;
...
};
在这个上下文中,= delete
是什么意思?
除了 = 0
和 = delete
之外,还有其他的“修饰符”吗?
删除一个函数是C++11的特性:
现在可以直接表达“禁止复制”的常见用法:
class X {
// ...
X& operator=(const X&) = delete; // Disallow copying
X(const X&) = delete;
};
[...]
“delete”机制可以用于任何函数。例如,我们可以使用它来消除不需要的转换,像这样:
struct Z {
// ...
Z(long long); // can initialize with a long long
Z(long) = delete; // but not anything less
};
= delete
比使用private
或其他类似机制更好,因为通常你希望这个被禁止的函数可以公开声明并且被考虑用于重载决议等,以便尽早失败并向用户提供最清晰的错误。任何涉及“隐藏”声明的解决方案都会降低此效果。 - Alex Celeste= 0
表示一个函数是纯虚函数,你无法从这个类中实例化对象。你需要继承它并实现这个方法。= delete
表示编译器不会为你生成那些构造函数。据我所知,这只允许在复制构造函数和赋值操作符上使用。但我对即将到来的标准不是太了解。=delete
语法还有其他用途。例如,您可以使用它来明确禁止某些可能发生的隐式转换。为此,只需删除重载函数即可。更多信息,请查看 C++0x 的维基百科页面。 - LiKao这段摘自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
机制是通用的,即它可以用于抑制任何操作。
是否还有其他 "修饰符"(除了
= 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)
如果您使用这6个之中的任何一个,只需注释掉相应的行即可。
例如:class 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)
// 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;
(现有答案的补充说明)
...而且已删除的函数必须是该函数的第一个声明(除了删除函数模板显式特化 - 删除应在特化的第一个声明处),这意味着您不能声明一个函数,然后在其定义局部于翻译单元时再将其删除。
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 )
虽然通常规则是避免专门化函数模板,因为特化不参与重载解析的第一步,但在某些情况下它可能会很有用。例如,使用一个没有定义的非重载主函数模板来匹配所有类型,其中一个不想将其隐式转换为其他匹配转换重载的类型;即通过只在未定义、非重载主函数模板的显式专门化中实现精确类型匹配来隐式地去除多个隐式转换匹配。
在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; */
}
= delete
是C++11引入的一个特性。根据=delete
,将不允许调用该函数。=delete
声明了某个成员函数,则该函数将无法被调用。Class ABC{
Int d;
Public:
ABC& operator= (const ABC& obj) =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;
}
待办事项:
default
和 delete
" 章节这是C++ 0x标准中的新功能,您可以删除继承的函数。
void foo(int); template <class T> void foo(T) = delete;
可以停止所有隐式转换。只有 int
类型的参数才会被接受,其他所有类型的参数都将尝试实例化一个“已删除”的函数。 - UncleBens
#define
,然后声明一个隐藏的函数什么的。 - Blindy