我理解在大多数情况下,我们不应该明确地调用析构函数。但是,我在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 发现我们不应该在局部变量上显式调用析构函数。
答案 0 :(得分:31)
在我看来,在这种情况下我们可以明确地调用析构函数,你能解释一下为什么吗?
你的意思是我们为什么可以?因为该语言允许对任何对象进行显式析构函数调用。正如你所说的,它通常会给出未定义的行为,因为大多数对象都会以其他方式被破坏,并且它是未定义的行为来销毁任何东西两次(或者更常见的是在破坏之后访问它)。但这只是意味着你不能这样做,而不是语言会妨碍你这样做。
或者你的意思是我们为什么要这样做?因为这就是你如何销毁由贴装新品创建的对象。
这个析构函数在这个例子中的含义是什么?
它们的意思相同,相当于p->~A()
;他们称对象为析构函数。该示例演示如果您愿意,可以在此处提供模板参数。我不确定你为什么要这样做。
除了放置删除之外,我们可以明确调用析构函数的情况是什么?
我认为你可以随时调用一个简单的析构函数(一个不做任何事情的析构函数);但没有意义。我认为摧毁使用placement new创建的东西是唯一合理的理由。
答案 1 :(得分:23)
在我看来,在这种情况下我们可以明确地调用析构函数,你能解释一下为什么吗?
因为语言允许随时调用任何对象的析构函数(假设您有访问权限,例如它不是私有析构函数)。
这个析构函数在这个例子中的含义是什么?
它只是调用析构函数。从逻辑上讲,这意味着该对象被破坏,应该被认为是该点上的垃圾,不应该被解除引用或使用。从技术上讲,它意味着对象处于析构函数离开它的任何状态,对于某些对象可能与默认构造相同(但你永远不应该依赖它)。
为什么他们合理?
有时您需要在不释放内存的情况下销毁对象。这种情况发生在很多类,如variant / any,各种脚本绑定和反射系统,一些单例实现等。
例如,您可以使用std::aligned_storage
为对象分配缓冲区,然后使用placement new在该缓冲区中构造对象。你无法在这个对象上调用delete
,因为这将调用析构函数并尝试释放支持它的内存。在这种情况下,你必须显式地调用析构函数才能正确地破坏对象。
除了展示位置删除之外,我们可以明确调用析构函数的情况是什么?
除了放置new之外的相应运算符之外,没有'placement delete'这样的东西(对delete
的任何调用都会隐式调用析构函数,除非编译器调用失败的构造,例如你的' placement delete'概念。)
我上面给出的一个例子。另一个例子是std::vector
。您可以调用pop_back()
之类的成员函数。这需要销毁向量中的最后一个元素,但它不能使用delete
,因为支持该对象的内存是必须单独管理的较大缓冲区的一部分。许多其他容器也是如此,例如开放寻址哈希表,deque
等。这是您希望使用template typename
以显式调用析构函数的示例。
这是一个特性,库的用户很少需要,但像STL甚至某些应用程序框架这样的低级库的实现者将需要在这里和那里使用。