Kno*_*abe 151 c++ user-defined-functions default-constructor deleted-functions c++11
我最初发布这个只是关于析构函数的问题,但现在我正在添加对默认构造函数的考虑.这是原始问题:
如果我想给我的类一个虚拟的析构函数,但是与编译器生成的析构函数相同,我可以使用
=default:Run Code Online (Sandbox Code Playgroud)class Widget { public: virtual ~Widget() = default; };但似乎我可以通过使用空定义减少输入来获得相同的效果:
Run Code Online (Sandbox Code Playgroud)class Widget { public: virtual ~Widget() {} };这两种定义的行为方式有何不同?
根据此问题的回复,默认构造函数的情况似乎相似.鉴于析构函数的" =default"和" {}"之间的含义几乎没有差异,默认构造函数的这些选项之间的含义几乎没有差别吗?也就是说,假设我想创建一个类型,其中该类型的对象将被创建和销毁,为什么我要说
Widget() = default;
Run Code Online (Sandbox Code Playgroud)
代替
Widget() {}
Run Code Online (Sandbox Code Playgroud)
?
如果在原始帖子违反某些SO规则后延长此问题,我深表歉意.为默认构造函数发布一个几乎完全相同的问题让我觉得不太理想.
Nic*_*las 91
在询问构造函数而不是析构函数时,这是一个完全不同的问题.
霍华德指出virtual,如果你的析构函数是,那么差异可以忽略不计.但是,如果你的析构函数是非虚拟的,那么这是一个完全不同的故事.构造函数也是如此.
使用= default特殊成员函数的语法(默认构造函数,复制/移动构造函数/赋值,析构函数等)意味着与简单操作非常不同{}.对于后者,该功能变为"用户提供".这改变了一切.
这是C++ 11定义的一个简单的类:
struct Trivial
{
int foo;
};
Run Code Online (Sandbox Code Playgroud)
如果尝试默认构造一个,编译器将自动生成默认构造函数.复制/移动和破坏也是如此.因为用户没有提供任何这些成员函数,所以C++ 11规范认为这是一个"普通"类.因此,这样做是合法的,比如记忆它们的内容以初始化它们等等.
这个:
struct NotTrivial
{
int foo;
NotTrivial() {}
};
Run Code Online (Sandbox Code Playgroud)
顾名思义,这不再是微不足道的.它有一个用户提供的默认构造函数.如果它是空的并不重要; 就C++ 11的规则而言,这不是一个微不足道的类型.
这个:
struct Trivial2
{
int foo;
Trivial2() = default;
};
Run Code Online (Sandbox Code Playgroud)
顾名思义,这是一个微不足道的类型.为什么?因为你告诉编译器自动生成默认构造函数.因此,构造函数不是"用户提供的".因此,类型计算为微不足道,因为它没有用户提供的默认构造函数.
该= default语法主要是有没有做的事情像拷贝构造函数/赋值,当您添加防止此类函数的创建成员函数.但它也会触发编译器的特殊行为,因此它在默认构造函数/析构函数中也很有用.
How*_*ant 40
它们都是非平凡的.
它们都具有相同的noexcept规范,具体取决于基础和成员的noexcept规范.
我到目前为止检测到的唯一区别是,如果Widget包含一个具有不可访问或删除的析构函数的基数或成员:
struct A
{
private:
~A();
};
class Widget {
A a_;
public:
#if 1
virtual ~Widget() = default;
#else
virtual ~Widget() {}
#endif
};
Run Code Online (Sandbox Code Playgroud)
然后=default解决方案将编译,但Widget不会是可破坏的类型.即如果你试图破坏一个Widget,你将得到一个编译时错误.但如果你不这样做,你就有了一个工作计划.
Otoh,如果你提供用户提供的析构函数,那么无论你是否破坏了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.
Run Code Online (Sandbox Code Playgroud)
4pi*_*ie0 30
之间的重要区别
class B {
public:
B(){}
int i;
int j;
};
Run Code Online (Sandbox Code Playgroud)
和
class B {
public:
B() = default;
int i;
int j;
};
Run Code Online (Sandbox Code Playgroud)
是否定义的默认构造函数B() = default;被认为是非用户定义的.这意味着在值初始化的情况下,如
B* pb = new B(); // use of () triggers value-initialization
Run Code Online (Sandbox Code Playgroud)
将完全不使用构造函数的特殊类型的初始化将发生,对于内置类型,这将导致零初始化.如果B(){}不发生这种情况.C++标准n3337 § 8.5/7说
对值类型T的对象进行值初始化意味着:
- 如果T是具有用户提供的构造函数 (12.1)的(可能是cv限定的)类类型(第9节),则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化是错误的);
- 如果T是一个(可能是cv限定的)非联合类类型 而没有用户提供的构造函数,那么该对象是零初始化的,如果T的隐式声明的默认构造函数是非平凡的,则调用该构造函数.
- 如果T是数组类型,则每个元素都是值初始化的; - 否则,对象被零初始化.
例如:
#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;
}
Run Code Online (Sandbox Code Playgroud)
可能的结果:
0,0
0,0
145084416,0
0,0
145084432,0
0,0
145084416,0
//...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
34039 次 |
| 最近记录: |