[英]Is destructor a normal function call?
Lets say I have two simple classes like this with non-virtual destructors: 可以说我有两个带有非虚拟析构函数的简单类:
struct A
{
~A() { std::cout << "A destructor" << std::endl; }
}
struct B : A
{
~B() { std::cout << "B destructor" << std::endl; }
}
When an instance of B
is destructed, the destructor of A
is called as well. 当
B
的实例被破坏时, A
的析构函数也被调用。 When I destruct an instance of B
through a pointer of type A*
then B
s destructor will not be called. 当我通过类型为
A*
的指针破坏B
的实例时,则不会调用B
的析构函数。 Does this also count for explicitly calling the destructor in a way you would also call a normal member function? 以您还调用普通成员函数的方式显式调用析构函数时,这是否也算在内?
struct A
{
~A() { std::cout << "Hello" << std::endl; }
void f() { std::cout << "Hello" << std::endl; }
}
A a;
a.~A(); // case 1
a.f(); // case 2
In this example, is there any difference between the two cases other than the name of the function that is called? 在此示例中,除了调用的函数名称之外,这两种情况之间是否有其他区别?
EDIT: Consider the same example with CRTP: 编辑:考虑与CRTP相同的示例:
template <typename C>
struct A
{
~A() { static_cast<C*>(this)->~C(); }
}
struct B : public A<B>
{
~B() { std::cout << "B destructor" << std::endl; }
}
A<B>* a = new B();
delete a;
Would this cause undefined behaviour or a memory leak? 这会导致不确定的行为或内存泄漏吗?
In fact, there are cases (ie: when using pools to avoid constant memory allocation), where you would normally call the destructor as a normal function, otherwise it would lead to undefined behaviour when you try to use placement new again on that memory address. 实际上,在某些情况下(即:使用池来避免不断分配内存时),通常会将析构函数作为常规函数调用,否则当您尝试再次在该内存地址上使用new放置时,它将导致未定义的行为。 。
T* Pool::alloc() {
...
return new (memory) T();
}
void Pool::dealloc( T* memory ) {
...
memory->~T();
}
Regarding to the non virtual destructor issue, if the destructor is not virtual, deleting a B
object inside a pointer to A, would lead to undefined behaviour. 关于非虚拟析构函数问题,如果析构函数不是虚拟的,则删除指向A的指针内的
B
对象将导致未定义的行为。
struct A
{
~A() { std::cout << "A destructor" << std::endl; }
};
struct B : A
{
~B() { std::cout << "B destructor" << std::endl; }
};
A* a = new B();
delete a; // undefined behaviour, just ~A() will be called
B* b = new B();
delete b; // it's OK because b is B*
More info in this FAQ 此常见问题解答中的更多信息
If you want to explicitly call a destructor, it has to be called from an object of the same type as the destructor being called. 如果要显式调用析构函数,则必须从与被调用析构函数相同类型的对象中调用它。 Otherwise, this will yield undefined behavior:
否则,这将产生未定义的行为:
In an explicit destructor call, the destructor name appears as a ~ followed by a type-name or decltypespecifier that denotes the destructor's class type.
在显式的析构函数调用中,析构函数名称显示为〜,后跟表示析构函数的类类型的type-name或decltypespecifier。 The invocation of a destructor is subject to the usual rules for member functions (9.3);
析构函数的调用受成员函数的常规规则约束(9.3); that is, if the object is not of the destructor's class type and not of a class derived from the destructor's class type (including when the destructor is invoked via a null pointer value), the program has undefined behavior.
也就是说,如果对象不是析构函数的类类型,也不是从析构函数的类类型派生的类(包括当通过空指针值调用析构函数时),则程序具有未定义的行为。
Also note that if explicitly calling a destructor, at the end of the scope where the instance resides, the destructor will implicitly be called a second time, provided that the object has been instanciated on the stack. 还要注意,如果在实例所在范围的末尾显式调用析构函数,则该析构函数将隐式调用第二次,前提是该对象已在堆栈上实例化。 That also yields undefined behavior:
这也会产生未定义的行为:
Once a destructor is invoked for an object, the object no longer exists;
一旦为一个对象调用了析构函数,该对象就不复存在了。 the behavior is undefined if the destructor is invoked for an object whose lifetime has ended (3.8).
如果为生存期已结束的对象调用析构函数,则行为未定义(3.8)。 [ Example: if the destructor for an automatic object is explicitly invoked, and the block is subsequently left in a manner that would ordinarily invoke implicit destruction of the object, the behavior is undefined
[示例:如果显式调用了自动对象的析构函数,并且随后以通常会隐式破坏对象的方式保留该块,则该行为是不确定的
I suggest you read section 12.4 of the spec. 我建议您阅读规范的12.4节。 The working draft is freely available.
工作草案可免费获得。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.