How is “=default” different from “{}” for default constructor and destructor?
我最初只是把它作为一个关于析构函数的问题发布,但现在我要添加对默认构造函数的考虑。以下是最初的问题:
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 :
1
2
3
4 class Widget {
public:
virtual ~Widget() = default;
};But it seems that I can get the same effect with less typing using an
empty definition:
1
2
3
4 class Widget {
public:
virtual ~Widget() {}
};Is there any way in which these two definitions behave differently?
基于针对这个问题发布的回复,默认构造函数的情况似乎类似。假设析构函数的"EDOCX1"(0)和"EDOCX1"(1)的含义几乎没有区别,那么默认构造函数的这些选项的含义也几乎没有区别吗?也就是说,假设我想创建一个类型,该类型的对象将同时被创建和销毁,我为什么要说
1 | Widget() = default; |
而不是
1 | Widget() {} |
?
如果在最初发布后扩展此问题违反了某些SO规则,我深表歉意。对于默认的构造函数发布一个几乎相同的问题让我觉得这是一个不太理想的选择。
这是一个与析构函数完全不同的问题。
如果你的析构函数是
对特殊成员函数(默认构造函数、复制/移动构造函数/赋值、析构函数等)使用
这是C++ 11定义的一个小类:
1 2 3 4 | struct Trivial { int foo; }; |
如果尝试使用默认的构造方法,编译器将自动生成默认的构造方法。复制/移动和销毁也是如此。因为用户没有提供这些成员函数中的任何一个,所以C++ 11规范认为这是一个"琐碎"类。因此,这样做是合法的,就像memcpy通过它们周围的内容来初始化它们等等。
这是:
1 2 3 4 5 6 | struct NotTrivial { int foo; NotTrivial() {} }; |
顾名思义,这不再是微不足道的。它有一个用户提供的默认构造函数。如果它是空的并不重要,就C++ 11的规则而言,这不能是微不足道的类型。
这是:
1 2 3 4 5 6 | struct Trivial2 { int foo; Trivial2() = default; }; |
顾名思义,这是一个微不足道的类型。为什么?因为您告诉编译器自动生成默认的构造函数。因此,构造函数不是"由用户提供的"。因此,类型计算起来很简单,因为它没有用户提供的默认构造函数。
当添加阻止创建此类函数的成员函数时,
它们都是不平凡的。
它们都具有相同的noexcept规范,这取决于基和成员的noexcept规范。
到目前为止,我检测到的唯一区别是,如果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | struct A { private: ~A(); }; class Widget { A a_; public: #if 1 virtual ~Widget() = default; #else virtual ~Widget() {} #endif }; |
然后将编译
但是,如果您提供用户提供的析构函数,那么无论您是否销毁
1 2 3 4 5 6 7 | 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. |
两者之间的重要区别
1 2 3 4 5 6 | class B { public: B(){} int i; int j; }; |
和
1 2 3 4 5 6 | class B { public: B() = default; int i; int j; }; |
使用
1 | B* pb = new B(); // use of () triggers value-initialization |
将发生完全不使用构造函数的特殊类型的初始化,对于内置类型,这将导致零初始化。如果是
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.
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #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; } |
可能的结果:
1 2 3 4 5 6 7 8 | 0,0 0,0 145084416,0 0,0 145084432,0 0,0 145084416,0 //... |
http://ideone.com/k8mbrd