请考虑以下代码:
#include <iostream>
class Test
{
public:
constexpr Test(const int x) : _x(x) {}
constexpr int get() const {return _x;}
~Test() {} // HERE
protected:
const int _x;
};
int main()
{
static constexpr Test test(5);
return 0;
}
如果删除行HERE
,代码编译得很好,但是如果我定义了一个空的析构函数,则会导致编译错误,指出Test
是非文字的。
为什么空的析构函数和根本没有析构函数有什么区别?
编辑:另一个相关问题:如果空和文字析构函数不同,如何定义受保护的文字析构函数?
答案 0 :(得分:20)
来自n3376的报价
7.1.5 / 9
对象声明中使用的constexpr说明符将对象声明为const。这样的对象应该有 字面类型,应初始化。如果它是由构造函数调用初始化的,那么该调用应该是一个常量 表达
3.9 / 10
如果符合以下类型,则为文字类型:
它有一个简单的析构函数......
12.4 / 5
如果析构函数不是用户提供的,并且如果:
,则析构函数是微不足道的- 析构函数不是虚拟的,
- 其类的所有直接基类都有简单的析构函数,
- 对于类的所有类型(或其数组)的非静态数据成员,每个都是这样的 class有一个简单的析构函数。
否则,析构函数是非常重要的。
clang诊断确实提供了更丰富的信息:
error: constexpr variable cannot have non-literal type 'const C'
'C' is not literal because it has a user-provided destructor
答案 1 :(得分:0)
没有析构函数会导致编译器添加一个普通的析构函数,这个析构函数在规范中定义不正确,但基本上什么也没做。
如果指定析构函数,则不会添加简单的析构函数。你的析构函数是非平凡的。
在你的情况下,Test::~Test() { }
看起来非常微不足道,但这是对你看到的内容的人类解释。为了更进一步,那么:
Test::~Test()
{
int a = 5;
}
我们可以看到优化器可以优化a,所以它显然什么都不做。怎么样:
Test::~Test()
{
for (int i = 0; i < 1000; i += 2) {
if ((i % 2) == 1)
doSomeSideEffect(); // like throwing or setting a global
}
}
我们可以看到i
永远不会是奇数,所以析构函数什么都不做。
规范必须定义什么是constexpr,什么不能。他们只是声明对constexpr足够好的唯一无所事事的析构函数是编译器提供的无关的析构函数,而不是沿着这个定义“无所事事”的兔子洞。