【问题标题】:Destructor call for scalar types & undefined behavior [duplicate]析构函数调用标量类型和未定义的行为
【发布时间】:2015-11-19 22:53:47
【问题描述】:

我刚刚编写了以下程序,它可以编译并运行良好。 (见现场演示here.

#include <iostream>
typedef int T;
int main()
{
    int a=3;
    std::cout<<a<<'\n';
    a.~T();
    std::cout<<a;
    return 0;
}

为什么程序编译得很好? 如果我没记错标量类型在 C++ 中没有构造函数和析构函数。那么,这个程序定义好了吗?在这种情况下,显式调用析构函数会破坏 variable a 还是会在函数执行完成时被编译器自动破坏?我知道在对象的生命周期结束后访问对象在 C++ 中具有未定义的行为。但是 C++ 标准对此有何规定?

我在 SO 上发现了类似的问题 here。 @Columbo 给出的答案是:

你不能为标量类型调用析构函数,因为它们没有 一。该语句仅适用于您在其中的模板代码 调用您不知道其类型的对象的析构函数 - 它 消除了为标量(甚至 数组)类型。

所以,我不明白他给出的解释。如果有人使用模板代码解释它会更好,其中析构函数被称为类型未知的对象。如果有人用简单的例子解释这一点,我将不胜感激。

【问题讨论】:

  • @vsoftco:为什么到目前为止还没有人给出答案?每次我发布任何问题时都很快,但这次看起来很慢。
  • 我已经链接到其他地方提出的完全相同的问题 - 尽管该问题还没有完整的答案,但它会因链接而受到影响
  • @vsoftco 好的,正在擦除
  • 如果该程序合法,有人可以发表评论吗?我们能否在基本类型上显式调用(平凡的)析构函数(即使我们通过typedef 调用它)? g++ 和 clang++ 都不会抱怨......
  • @vsoftco 这是合法的,哥伦布的链接答案说明了为什么......当你进行伪析构函数调用时,就像上面的例子一样,唯一发生的事情就是左边的表达式点被评估。 IOW,析构函数调用本身就是一个 NOP。

标签: c++ destructor undefined-behavior built-in-types explicit-destructor-call


【解决方案1】:

根据this

普通析构函数是不执行任何操作的析构函数。 具有普通析构函数的对象不需要删除表达式,并且可以通过简单地释放它们的存储来处理。 所有与 C 语言兼容的数据类型(POD 类型)都可以简单地破坏。

这可能类似于在 C++ 中,您可以像任何类类型对象一样初始化任何 POD 类型对象,方法是使用 (init_val) 调用其构造函数,例如 int i(-1);

但请注意,根据定义直接为普通对象(例如局部变量)调用析构函数,会在作用域结束时再次调用析构函数时调用未定义的行为。

【讨论】:

  • 那里的“不采取行动”确实意味着它所说的。一个简单的析构函数可以被多次调用或根本不被调用,这没有区别。 (没有 UB。)
  • @Potatoswatter 在 12.4 中 trivial destructor 的定义表明只有类类型可以具有析构函数(更不用说普通析构函数了,它是非用户声明的析构函数满足特定要求的类)
  • @AlexLop。您的回答似乎自相矛盾,您是说 OP 的代码会导致未定义的行为吗?
  • @Potatoswatter 所以你说 OP 的代码在其生命周期结束后通过访问 a 导致 UB(因为微不足道的析构函数结束了它们对象的生命周期,你说伪析构函数调用有相同的语义)。然而,哥伦布在重复线程上的回答似乎是说它不会导致 UB,因为伪析构函数没有效果,尽管他对此并不完全清楚。
  • @Potatoswatter 好的,我现在看到具有普通析构函数的类类型的对象不会通过调用它们的析构函数来结束其生命周期。所以struct A { int x; } a; a.~A(); a.~A(); 是合法的。
猜你喜欢
  • 2014-08-26
  • 2015-08-22
  • 2020-09-25
  • 2013-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多