显式调用析构函数

calling destructor explicitly

本文关键字:析构函数 调用      更新时间:2023-10-16

我理解在大多数情况下,不应该显式地调用析构函数。然而,我在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时,还有哪些情况下可以显式调用析构函数?

谢谢。

EDIT:我从c++ FAQ中发现,我们不应该在局部变量上显式调用析构函数。

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

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

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

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

它们的意思相同,等价于p->~A();它们调用对象的析构函数。该示例演示了如果您愿意,可以在这里提供模板参数。我不知道你为什么想要。

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

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

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

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

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

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

为什么它们是合理的?

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

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

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

没有真正的"放置删除"这样的事情,除了相应的操作符安置新(和任何调用delete将隐式调用析构函数,除了那些编译器调用失败的构造,例如你的"放置删除"的概念)。

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

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