【问题标题】:calling destructor explicitly显式调用析构函数
【发布时间】:2021-01-28 04:24:13
【问题描述】:

我知道在大多数情况下,我们不应该显式调用析构函数。但是,我看到了一个来自 C++11 Standard N3485 Section 13.4.5 Template arguments 的示例:

对具有以下类型的对象的显式析构函数调用 是一个类模板特化可以显式指定 模板参数。示例:

template<class T> struct A {
    ~A();
}; 

void f(A<int>* p, A<int>* q) {
    p->A<int>::~A();      // OK: destructor call
    q->A<int>::~A<int>(); // OK: destructor call
}

在我看来,在这种情况下我们可以显式调用析构函数,你能解释一下为什么吗?在这个例子中,这些析构函数调用是什么意思?为什么它们是合理的?

另一个问题:

除了实现placement delete之外,还有哪些情况可以显式调用析构函数?

谢谢。

编辑:我从 C++ FAQ 发现我们不应该在局部变量上显式调用析构函数。

【问题讨论】:

  • 引用的帖子是关于在局部变量上显式调用析构函数,其析构函数也会在其作用域结束时再次隐式调用。
  • +1 我在我的代码中做了一些类似的废话,明确调用析构函数来销毁我的对象(或者至少它似乎有效)。但我已经在托管类型上完成了。看到答案会很有趣
  • @AndyThomas-Cramer 我理解,我的意思是引用关于显式析构函数调用标准的答案的解释。我的帖子有误导性吗?如果这是一个问题,我会尝试改写它。
  • @taocp - 在这里澄清一下,正如在引用的帖子中,未定义的行为没有显式调用析构函数 - 它导致它在同一个对象上被调用不止一次 i>.
  • @AndyThomas-Cramer 啊,我同意。我主要看答案。我会尝试纠正它。谢谢!

标签: c++ destructor


【解决方案1】:

在我看来,在这种情况下我们可以显式调用析构函数,你能解释一下为什么吗?

你的意思是我们为什么可以?因为该语言允许对任何对象进行显式析构函数调用。正如您所说,它通常会给出未定义的行为,因为大多数对象将以其他方式被销毁,并且两次销毁任何东西(或更一般地在销毁后访问它)是未定义的行为。但这只是意味着你不能这样做,并不是说语言会阻止你这样做。

或者你的意思是我们为什么要这样做?因为这就是你销毁由placement new 创建的对象的方式。

在这个例子中,这些析构函数调用是什么意思?

它们都是同一个意思,相当于p-&gt;~A();他们调用对象的析构函数。该示例演示了如果您愿意,可以在此处提供模板参数。我不知道你为什么想要。

除了放置删除,还有哪些情况可以显式调用析构函数?

认为你可以随时调用一个微不足道的析构函数(一个不做任何事情的析构函数);但没有意义。我认为销毁使用placement new 创建的东西是这样做的唯一正当理由。

【讨论】:

  • 对于已分配存储的对象是否同样适用?我在 Win 表单上做过一次,我显式调用析构函数来销毁 Form 对象,但如果它的 UB 那么我知道我必须改变现在的代码。
  • +1。此外,您对普通析构函数是正确的,因为 §3.8/1 定义了具有普通析构函数的对象的生命周期不会在调用析构函数时结束,而是在重用或释放该对象的存储时结束
  • @AndyProwl 你能否结束我的评论。:)
  • @Koushik:Win 是 .NET 的东西吗?这对我来说是未知的领域:)
  • @AndyProwl 哦,是的:) 澄清一下这个安迪。如果你不对分配的对象调用 delete 而是调用它的析构函数,那么程序有多好?
【解决方案2】:

在我看来,在这种情况下我们可以显式调用析构函数,你能解释一下为什么吗?

因为语言允许它可以随时调用任何对象的析构函数(假设你有访问权限,例如它不是私有析构函数)。

在这个例子中这些析构函数调用是什么意思?

它只是调用析构函数。从逻辑上讲,这意味着该对象已被破坏,从那时起应该被视为垃圾,不应取消引用或使用。从技术上讲,这意味着对象处于析构函数将其保留的任何状态,对于某些对象可能与默认构造相同(但你永远不应该依赖它)。

为什么它们是合理的?

有时您需要在不释放内存的情况下销毁对象。这发生在很多类中,比如变体/任何、各种脚本绑定和反射系统、一些单例实现等。

例如,您可以使用std::aligned_storage 为对象分配缓冲区,然后使用placement new 在该缓冲区中构造对象。您不能在此对象上调用delete,因为这将调用析构函数并尝试释放支持它的内存。在这种情况下,您必须显式调用析构函数以正确地析构对象。

除了placement delete,还有哪些我们可以显式调用析构函数的情况?

实际上并没有“放置删除”之类的东西,除了放置新的相应运算符(并且任何对delete 的调用都将隐式调用析构函数,除了编译器为构造失败调用的那些,例如你的“放置删除” ' 概念)。

我在上面给出的一个例子。另一个例子是std::vector。您可以调用pop_back() 等成员函数。这需要销毁向量中的最后一个元素,但它不能使用delete,因为支持对象的内存是必须单独管理的更大缓冲区的一部分。许多其他容器也是如此,例如开放寻址哈希表、deque 等。这是您希望使用template typename 来显式调用析构函数的示例。

这是一个库的用户很少需要的功能,但是像 STL 甚至一些应用程序框架这样的低级库的实现者将需要在这里和那里使用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-05
    • 1970-01-01
    • 2012-08-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多