当前位置: 首页 > 知识库问答 >
问题:

为什么析构函数不能标记为constexpr?

宰父涵忍
2023-03-14

在C中,您可以将许多内容声明为Constexr:变量、函数(包括成员函数和运算符)、构造函数,以及从C 1z开始的if语句和lambda表达式。但是,声明析构函数Constexr会导致错误:

struct X {
    constexpr ~X() = default; // error: a destructor cannot be 'constexpr'
};

我的问题:

  1. 为什么不能将析构函数标记为constexpr
  2. 如果我没有提供析构函数,那么隐式生成的析构函数是constexpr吗
  3. 如果我声明一个默认析构函数(~X()=默认值 ),是否自动执行

共有3个答案

卫兴邦
2023-03-14

从C 20开始,构造函数可以标记为constexpr;我不知道它是否明确表示“析构函数可能是constexpr”,但标准草案在第9.2.5节第5段中包含以下文本:

函数体不是delete的constexpr析构函数的定义还应满足以下要求:

  • 对于类类型或其(可能是多维)数组的每个子对象,该类类型应具有constexpr析构函数

这现在也有了一个有用的功能,因为C 20还允许在constexpr上下文中新建和删除,允许像向量和字符串这样的东西在编译时工作,而不需要黑客攻击(虽然我认为C 20实际上没有包括对标准库的更改来实现这一点,但有可能实现与向量在编译时完全工作的API和行为相同的东西)。

夹谷信鸿
2023-03-14

如果你要找的是限制背后的推理,看看这篇论文,它清楚地指出限制是人为的——析构函数没有内在的属性来阻止它们在Constexr上下文中工作,事实上编译器实现者同意在Constexr上下文中支持它们是微不足道的。

我猜C标准委员会最初将限制放在C 11中,因为当时他们不想处理析构函数,更容易完全排除它们。

廖君昊
2023-03-14

根据草案basic.types#10可能是具有以下所有属性的cv限定类类型:

可能具有以下所有属性的cv限定类类型:

(10.5.1)-它有一个微不足道的析构函数,

(10.5.2)-它要么是闭包类型,要么是聚合类型,要么至少有一个非复制或移动构造函数的constexpr构造函数或构造函数模板(可能继承自基类),

(10.5.3)-如果是并集,则其至少一个非静态数据成员为非易失性文字类型

(10.5.4)-如果它不是联合,则其所有非静态数据成员和基类都是非易失性文字类型。

问题1:为什么析构函数不能标记为constexpr?

因为只有微不足道的析构函数才有资格用于构造。以下是草案的相关部分

如果析构函数不是用户提供的,并且满足以下条件,则析构函数是微不足道的:

(5.4)-析构函数不是虚拟的,

(5.5)-其类的所有直接基类都有平凡析构函数,并且

(5.6)-对于其类中属于类类型(或其数组)的所有非静态数据成员,每个此类类都有一个简单的析构函数。

否则,析构函数是非平凡的。

问题2:如果我没有提供析构函数,那么隐式生成的析构函数是否为constexpr?

是的,因为隐式生成的析构函数是平凡类型,所以它适用于constexpr

问题3:如果我声明一个默认析构函数(~X()=default;),它是自动constexpr吗?

实际上,这个析构函数是用户声明并隐式生成的,因此它符合constexpr的条件。

我找不到任何直接引用,只有平凡的析构函数才符合constexpr的条件,但是如果析构函数不是平凡的,那么可以肯定的是类类型不是cv限定的

从C 20开始,用户定义的析构函数在某些条件下也可以被构造。

dcl。constexpr/3:

constexpr函数的定义应满足以下要求:

  • 其返回类型(如果有)应为文字类型;
  • 它的每个参数类型都应该是文字类型;
  • 不得协程([dcl.fct.def.coroutine ]);
  • 如果函数是构造函数或析构函数,则其类不得有任何虚拟基类;
  • 其功能体不得包含([stmt.pre])
    • goto语句,
    • 标识符标签([stmt.label ]),
    • 非文字类型或静态或线程存储持续时间的变量的定义。

 类似资料:
  • 使用scandir()函数时,我收到以下php警告: Scandir无法打开目录:公共html/page2中不允许操作。php在线3 第2页。php 我想使用这个功能来打印我的根文件夹的文件和子目录,但它不工作。 有人知道怎么修吗?

  • 请考虑以下程序: 如果我运行该程序,我会得到(GoBolt): ...这符合我的预期。但是,如果在线上我将析构函数标记为可能抛出,那么我得到: ...即使用复制因子代替移动因子。为什么会这样呢?复制似乎不能防止移动所必须的破坏。 相关问题: < li >是否要求std::vector使用移动而不是复制? < li >当向量增长时,如何实施移动语义? < li >向量重新分配使用复制而不是移动构造函

  • 本文向大家介绍请你回答一下为什么析构函数必须是虚函数?为什么C++默认的析构函数不是虚函数?相关面试题,主要包含被问及请你回答一下为什么析构函数必须是虚函数?为什么C++默认的析构函数不是虚函数?时的应答技巧和注意事项,需要的朋友参考一下 将可能会被继承的父类的析构函数设置为虚函数,可以保证当我们new一个子类,然后使用基类指针指向该子类对象,释放基类指针时可以释放掉子类的空间,防止内存泄漏。  

  • 我读到虚拟析构函数必须在具有虚拟方法的类中声明。我只是不明白为什么必须宣布它们是虚拟的。我从下面的例子中知道为什么我们需要虚拟析构函数。我只是想知道为什么编译器不为我们管理虚拟析构函数。关于虚拟析构函数的工作,有什么我需要知道的吗?以下示例显示,如果析构函数未声明为虚拟,则派生类的析构函数不会被调用,这是为什么?

  • 问题内容: 为什么Java中的构造函数不能是final,static或abstract? 例如,您可以向我解释为什么这无效吗? 问题答案: 当您设置方法时,其含义是: “我不希望任何类覆盖它。” 但是根据Java语言规范: JLS 8.8- “构造函数声明不是成员。它们从不继承,因此不受隐藏或覆盖。” 当您设置方法时,其含义是: “此方法没有主体,应在子类中实现。” 但是,使用关键字时会隐式调用构

  • 预计此函数将无法typeCheck。然而,没有解释发生这种情况的原因。在GHCI中试用时,我得到了以下输出: 为什么会出现这种情况?