C/C++C++11新特性:=default 和 =delete
Posted mick_seu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C/C++C++11新特性:=default 和 =delete相关的知识,希望对你有一定的参考价值。
参考自:微软文档显式默认设置的函数和已删除的函数
C++11 标准新特性:Defaulted 和 Deleted 函数
C++11以前,我们习惯将拷贝构造函数和拷贝赋值函数设置为 private 来禁止类的拷贝行为。
class noncopyable
public:
noncopyable() ;
private:
noncopyable(const noncopyable&);
noncopyable& operator=(const noncopyable&);
;
在 C++11 之前,此代码段是不可复制的类型的惯例形式。 但是,它具有几个问题:
-
拷贝构造函数必须以私有方式进行声明以隐藏它,但因为它进行了完全声明,所以会阻止自动生成默认构造函数。 如果你需要默认构造函数,则必须显式定义一个(即使它不执行任何操作)。
-
即使显式定义的默认构造函数不执行任何操作,编译器也会将它视为重要内容。 其效率低于自动生成的默认构造函数,并且会阻止
noncopyable
成为真正的 POD 类型。 -
尽管拷贝构造函数和复制赋值函数在外部代码中是隐藏的,但成员函数和
noncopyable
的友元仍可以看见并调用它们。 如果它们进行了声明但是未定义,则调用它们会导致链接器错误。 -
虽然这是广为接受的惯例,但是除非你了解用于自动生成特殊成员函数的所有规则,否则意图不明确
如今,C++11提供了 = delete 来显式禁止我们想要禁止生成的函数。相对的, = default 则用来显式生成默认函数。
class noncopyable
public:
noncopyable() =default;
noncopyable(const noncopyable&) =delete;
noncopyable& operator=(const noncopyable&) =delete;
;
虽然只显式的禁用了一个拷贝构造函数和拷贝赋值函数,但是由于编译器检测到类存在用户自定义的拷贝构造函数与拷贝赋值函数的声明,所以不会再隐式的生成其它参数类型的拷贝构造函数及拷贝赋值函数,所以对象间的拷贝构造和拷贝赋值被完全禁止了。
请注意如何解决与 C++11 之前的惯例有关的问题:
-
仍可通过声明拷贝构造函数来阻止生成默认构造函数,但可通过将其显式设置为默认值进行恢复。
-
显式设置的默认特殊成员函数仍被视为不重要的,因此性能不会下降,并且不会阻止
noncopyable
成为真正的 POD 类型。 -
拷贝构造函数和拷贝赋值函数是公共的,但是已删除。 定义或调用已删除函数是编译时错误。
-
对于了解
=default
和=delete
的人来说,意图是非常清楚的。 你不必了解用于自动生成特殊成员函数的规则。
我们知道,在我们作出如下定义后:
class Base ;
编译器将自动为该类型生成默认构造函数、拷贝构造函数、拷贝赋值函数和析构函数。
此外,还有如下潜规则需要知道:
-
如果显式声明了任何构造函数,则不会自动生成默认构造函数。
-
如果显式声明了虚拟析构函数,则不会自动生成默认析构函数。
-
如果显式声明了移动构造函数或移动赋值函数,则:
-
不自动生成拷贝构造函数。
-
不自动生成拷贝赋值运算符。
-
-
如果显式声明了拷贝构造函数、拷贝赋值运算符、移动构造函数、移动赋值函数或析构函数,则:
-
不自动生成移动构造函数。
-
不自动生成移动赋值运算符。
-
关于delete还有两个有用的地方是
1)让你的对象只能生成在栈内存上:
structNonNewable
void*operatornew(std::size_t) = delete;
;
2)阻止函数的其形参的类型调用:(若尝试以 double 的形参调用
f()
,将会引发编译期错误, 编译器不会自动将 double 形参转型为 int 再调用
f()
,如果传入的参数是double,则会出现编译错误)
voidf(inti);
voidf(double) = delete;
以上是关于C/C++C++11新特性:=default 和 =delete的主要内容,如果未能解决你的问题,请参考以下文章
转C++11 标准新特性:Defaulted 和 Deleted 函数