C++ 默认构造函数和析构函数的“=default”与“{}”有何不同?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13576055/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How is "=default" different from "{}" for default constructor and destructor?
提问by KnowItAllWannabe
I originally posted this as a question only about destructors, but now I'm adding consideration of the default constructor. Here's the original question:
我最初将此作为一个关于析构函数的问题发布,但现在我正在考虑默认构造函数。这是原始问题:
If I want to give my class a destructor that is virtual, but is otherwise the same as what the compiler would generate, I can use
=default
:class Widget { public: virtual ~Widget() = default; };
But it seems that I can get the same effect with less typing using an empty definition:
class Widget { public: virtual ~Widget() {} };
Is there any way in which these two definitions behave differently?
如果我想给我的类一个虚拟的析构函数,但在其他方面与编译器生成的相同,我可以使用
=default
:class Widget { public: virtual ~Widget() = default; };
但似乎我可以通过使用空定义减少输入来获得相同的效果:
class Widget { public: virtual ~Widget() {} };
这两个定义有什么不同的表现吗?
Based on the replies posted for this question, the situation for the default constructor seems similar. Given that there is almost no difference in meaning between "=default
" and "{}
" for destructors, is there similarly almost no difference in meaning between these options for default constructors? That is, assuming I want to create a type where the objects of that type will be both created and destroyed, why would I want to say
根据针对此问题发布的回复,默认构造函数的情况似乎类似。鉴于析构函数的" =default
" 和 " {}
" 之间的含义几乎没有区别,那么默认构造函数的这些选项之间的含义是否也几乎没有区别?也就是说,假设我想创建一个类型,该类型的对象将被创建和销毁,我为什么要说
Widget() = default;
instead of
代替
Widget() {}
?
?
I apologize if extending this question after its original posting is violating some SO rules. Posting an almost-identical question for default constructors struck me as the less desirable option.
如果在原始发布后扩展此问题违反了某些 SO 规则,我深表歉意。为默认构造函数发布一个几乎相同的问题让我觉得不太理想。
采纳答案by Nicol Bolas
This is a completely different question when asking about constructors than destructors.
当询问构造函数而不是析构函数时,这是一个完全不同的问题。
If your destructor is virtual
, then the difference is negligible, as Howard pointed out. However, if your destructor was non-virtual, it's a completely different story. The same is true of constructors.
如果您的析构函数是virtual
,那么差异可以忽略不计,正如霍华德指出的那样。但是,如果您的析构函数是non-virtual,则情况完全不同。构造函数也是如此。
Using = default
syntax for special member functions (default constructor, copy/move constructors/assignment, destructors etc) means something very different from simply doing {}
. With the latter, the function becomes "user-provided". And that changes everything.
= default
对特殊成员函数(默认构造函数、复制/移动构造函数/赋值、析构函数等)使用语法意味着与简单地执行{}
. 对于后者,该功能变为“用户提供”。这改变了一切。
This is a trivial class by C++11's definition:
根据 C++11 的定义,这是一个微不足道的类:
struct Trivial
{
int foo;
};
If you attempt to default construct one, the compiler will generate a default constructor automatically. Same goes for copy/movement and destructing. Because the user did not provide any of these member functions, the C++11 specification considers this a "trivial" class. It therefore legal to do this, like memcpy their contents around to initialize them and so forth.
如果您尝试默认构造一个,编译器将自动生成一个默认构造函数。复制/移动和破坏也是如此。因为用户没有提供任何这些成员函数,C++11 规范认为这是一个“平凡”的类。因此,这样做是合法的,比如 memcpy 他们的内容来初始化它们等等。
This:
这个:
struct NotTrivial
{
int foo;
NotTrivial() {}
};
As the name suggests, this is no longer trivial. It has a default constructor that is user-provided. It doesn't matter if it's empty; as far as the rules of C++11 are concerned, this cannot be a trivial type.
顾名思义,这不再是微不足道的。它有一个由用户提供的默认构造函数。是否为空也没有关系;就 C++11 的规则而言,这不是一个微不足道的类型。
This:
这个:
struct Trivial2
{
int foo;
Trivial2() = default;
};
Again as the name suggests, this is a trivial type. Why? Because you told the compiler to automatically generate the default constructor. The constructor is therefore not "user-provided." And therefore, the type counts as trivial, since it doesn't have a user-provided default constructor.
顾名思义,这是一个微不足道的类型。为什么?因为你告诉编译器自动生成默认构造函数。因此构造函数不是“用户提供的”。因此,该类型被视为微不足道的,因为它没有用户提供的默认构造函数。
The = default
syntax is mainly there for doing things like copy constructors/assignment, when you add member functions that prevent the creation of such functions. But it also triggers special behavior from the compiler, so it's useful in default constructors/destructors too.
该= default
语法主要是有没有做的事情像拷贝构造函数/赋值,当您添加防止此类函数的创建成员函数。但它也会触发编译器的特殊行为,因此它在默认构造函数/析构函数中也很有用。
回答by Howard Hinnant
They are both non-trivial.
他们都是不平凡的。
They both have the same noexcept specification depending upon the noexcept specification of the bases and members.
它们都具有相同的 noexcept 规范,具体取决于基础和成员的 noexcept 规范。
The only difference I'm detecting so far is that if Widget
contains a base or member with an inaccessible or deleted destructor:
到目前为止,我检测到的唯一区别是 ifWidget
包含具有不可访问或已删除析构函数的基类或成员:
struct A
{
private:
~A();
};
class Widget {
A a_;
public:
#if 1
virtual ~Widget() = default;
#else
virtual ~Widget() {}
#endif
};
Then the =default
solution will compile, but Widget
won't be a destructible type. I.e. if you try to destruct a Widget
, you'll get a compile-time error. But if you don't, you've got a working program.
然后=default
解决方案将编译,但Widget
不会是可破坏的类型。也就是说,如果你试图破坏一个Widget
,你会得到一个编译时错误。但如果你不这样做,你就有了一个工作程序。
Otoh, if you supply the user-provideddestructor, then things won't compile whether or not you destruct a Widget
:
Otoh,如果您提供用户提供的析构函数,那么无论您是否析构 a 都不会编译Widget
:
test.cpp:8:7: error: field of type 'A' has private destructor
A a_;
^
test.cpp:4:5: note: declared private here
~A();
^
1 error generated.
回答by 4pie0
The important difference between
之间的重要区别
class B {
public:
B(){}
int i;
int j;
};
and
和
class B {
public:
B() = default;
int i;
int j;
};
is that default constructor defined with B() = default;
is considered not-user defined. This means that in case of value-initializationas in
是定义的默认构造函数B() = default;
被认为是非用户定义的。这意味着,在的情况下的值初始化为
B* pb = new B(); // use of () triggers value-initialization
special kind of initialization that doesn't use a constructor at all will take place and for built-in types this will result in zero-initialization. In case of B(){}
this won't take place. The C++ Standard n3337 §8.5/7 says
将发生根本不使用构造函数的特殊类型的初始化,对于内置类型,这将导致零初始化。在B(){}
这种情况下不会发生。C++ 标准 n3337 §8.5/7 说
To value-initialize an object of type T means:
— if T is a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor(12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
— if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, if T's implicitly-declared default constructor is non-trivial, that constructor is called.
— if T is an array type, then each element is value-initialized; — otherwise, the object is zero-initialized.
对 T 类型的对象进行值初始化意味着:
— 如果 T 是一个(可能是 cv 限定的)类类型(第 9 条),具有用户提供的构造函数(12.1),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数,则初始化是格式错误的);
— 如果 T 是(可能是 cv 限定的)非联合类类型, 没有用户提供的构造函数,则对象是零初始化的,如果 T 隐式声明的默认构造函数是非平凡的,则调用该构造函数。
— 如果 T 是数组类型,则每个元素都进行了值初始化;— 否则,对象是零初始化的。
For example:
例如:
#include <iostream>
class A {
public:
A(){}
int i;
int j;
};
class B {
public:
B() = default;
int i;
int j;
};
int main()
{
for( int i = 0; i < 100; ++i) {
A* pa = new A();
B* pb = new B();
std::cout << pa->i << "," << pa->j << std::endl;
std::cout << pb->i << "," << pb->j << std::endl;
delete pa;
delete pb;
}
return 0;
}
possible result:
可能的结果:
0,0
0,0
145084416,0
0,0
145084432,0
0,0
145084416,0
//...