简体   繁体   English

析构函数是正常的函数调用吗?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM