【问题标题】:Pseudo-destructor call does not destroy an object伪析构函数调用不会破坏对象
【发布时间】:2018-03-10 09:36:26
【问题描述】:

考虑以下代码:

#include <iostream>

typedef int t;
t a=42;

int main()
{
    a.t::~t();
    std::cout << a; //42
}

我预计a 将被销毁。但事实并非如此,为什么呢?那个伪析构函数调用会如何销毁对象?

【问题讨论】:

  • 如果它被“摧毁”了,你会期待什么?在对象的生命周期结束后访问对象具有未定义的行为。
  • 请定义“销毁”。您预计会发生什么/不会发生什么?
  • @Mankarse 我预计没有 a 表示的对象。但是 a 仍然表示一个 int 类型的对象,其值等于 42
  • @DmitryFucintv:嗯……如果它被破坏了,代码会有未定义的行为。该标准对包含未定义行为的代码施加无要求,因此a 仍表示具有值42int 将是对代码的一种可能解释(如果代码确实导致a 的生命周期结束)。

标签: c++ language-lawyer destructor primitive-types explicit-destructor-call


【解决方案1】:

但事实并非如此,为什么?

§5.2.4/1:

唯一的作用是对点或箭头之前的后缀表达式求值。

其中后缀表达式是发生调用的对象的表达式。因此,伪析构函数调用,作为对普通析构函数的调用,不会结束它所应用的对象的生命周期。例如,

int i = 0;
(i += 5).~decltype(i)();
std::cout << i;

您实际上不能为标量调用析构函数,因为它们没有析构函数(参见 [class.dtor])。该语句仅适用于模板代码,其中您调用了您不知道其类型的对象的析构函数 - 它消除了为标量类型编写专门化的必要性。


在 cmets 中注意到 [expr.pseudo] 确实暗示了标量的析构函数的存在

在点 . 或箭头 -&gt; 运算符之后使用 pseudo-destructor-name 表示由 type-name 命名的非类类型的析构函数。

但是,这与标准的其他部分不一致,例如§12,将析构函数称为特殊成员函数并提到

析构函数用于销毁其类类型的对象。

这似乎是在 C++98 天创造的不精确性。

【讨论】:

  • +1 这是正确答案。它会通过扩展标准参考得到改进(您引用的部分不足以完全理解行为)。
  • @DmitryFucintv 添加了解释。并且代码示例在 Clang 下编译得很好,GCC 只是在这里有一个 bug
  • 标准规定“在点 . 或箭头 -> 运算符之后使用伪析构函数名称表示由 type-name 或 decltype-specifier 表示的非类类型的析构函数。”这表明该类型确实具有析构函数。 (如果它没有析构函数,则无法表示其析构函数)。然而 12.4 似乎说没有非类类型的析构函数。也许“代表析构函数”的文字只是草率的措辞。
  • @Matt 访问 a 很好,因为 a 的生命周期不会按照 3.8 的规定结束。措辞可能很草率,是的。一旦我回来并拥有一台笔记本电脑,我可能会扩展答案。
  • @PravasiMeet 没有“伪析构函数”之类的东西,伪析构函数调用根本不调用任何东西——调用是伪的,而不是析构函数。简单的析构函数只是一个不执行任何操作的析构函数(即无操作)。
猜你喜欢
  • 2011-11-15
  • 2022-01-23
  • 2011-01-25
  • 2013-09-27
  • 2011-04-30
  • 2015-08-12
  • 1970-01-01
  • 2019-03-01
相关资源
最近更新 更多