C++ 显式调用析构函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16720201/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 20:35:29  来源:igfitidea点击:

calling destructor explicitly

c++destructor

提问by taocp

I understand that in most cases, we should not call a destructor explicitly. However, I saw an example from C++11 Standard N3485 Section 13.4.5 Template arguments:

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

An explicit destructor call for an object that has a type that is a class template specialization may explicitly specify the template-arguments. Example:

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
}

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

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
}

It seems to me that we can call destructor explicitly in this case, could you explain to me why? What does those destructor call mean in this example? Why they are reasonable?

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

Another question:

另一个问题:

What are the cases that we can call destructors explicitly besides when we are implementing placement delete?

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

Thank you.

谢谢你。

EDIT:I found from C++ FAQ that we should not explicitly call a destructor on a local variable.

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

采纳答案by Mike Seymour

It seems to me that we can call destructor explicitly in this case, could you explain to me why?

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

Do you mean why can we? Because the language allows explicit destructor calls on any object. As you say, it usually gives undefined behaviour since most objects will be destroyed in some other way, and it's undefined behaviour to destroy anything twice (or more generally to access it after destruction). But that just means that you mustn't do it, not that the language will prevent you from doing it.

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

Or do you mean why would we want to? Because that's how you destroy an object created by placement new.

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

What does those destructor call mean in this example?

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

They both mean the same thing, and are equivalent to p->~A(); they call the object's destructor. The example is demonstrating that you can provide template arguments here if you want to. I'm not sure why you'd want to.

它们都意味着相同的事情,并且等价于p->~A(); 他们调用对象的析构函数。该示例表明您可以根据需要在此处提供模板参数。我不确定你为什么想要。

What are the cases that we can call destructors explicitly besides placement delete?

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

I thinkthat you're allowed to call a trivial destructor (one that doesn't do anything) whenever you like; but there's no point. I think destroying something created with placement new is the only legitimate reason to do it.

认为你可以随时调用一个简单的析构函数(一个什么都不做的);但没有意义。我认为销毁用placement new 创建的东西是唯一合法的理由。

回答by Sean Middleditch

It seems to me that we can call destructor explicitly in this case, could you explain to me why?

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

Because it's allowed by the language to be able to invoke the destructor of any object whenever you want (assuming you have access, e.g. it's not a private destructor).

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

What does those destructor call mean in this example?

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

It just invokes the destructor. Logically, it means that the object is destructed and should be considered to be garbage from that point on and should not be dereferenced or used. Technically it means that the object is in whatever state the destructor leaves it in, which for some objects maybe identical to default construction (but you should never, ever rely on that).

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

Why they are reasonable?

为什么它们是合理的?

Sometimes you need to destroy objects without releasing their memory. This happens in a lot of class like variant/any, various script binding and reflection system, some singleton implementations, etc.

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

For example, you might use std::aligned_storageto allocate a buffer for an object and then use placement new to construct an object in that buffer. You cannot call deleteon this object since that will both invoke the destructor and try to free the memory backing it. You mustexplicitly invoke the destructor in this case to properly destruct the object.

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

What are the cases that we can call destructors explicitly besides placement delete?

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

There's not really such a thing as 'placement delete', other than the corresponding operator to placement new (and any calls to deletewill implicitly invoke the destructor except those the compiler invokes for failed construction, e.g. your 'placement delete' notion).

除了放置 new 的相应操作符之外,并没有真正的“放置删除”这样的东西(并且任何调用都delete将隐式调用析构函数,除了编译器因构造失败而调用的那些,例如您的“放置删除”概念)。

One example I gave above. Another example is std::vector. You can call member functions like pop_back(). This needs to destroy the last element in the vector but it can't use deletesince the memory backing the object is part of a larger buffer that must be managed separately. The same goes for many other containers, like open-addressing hash tables, deque, and so on. This is an example of where you'd want to use the template typenamein order to invoke the destructor explicitly.

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

It's a feature that a user of a library is very rarely going to need but the implementor of a low-level library like the STL or even some application frameworks is going to need to use here and there.

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