A destructor is a special member function that is called when the lifetime of an object ends. The purpose of the destructor is to free the resources that the object may have acquired during its lifetime.
~ class_name (); | (1) | |
virtual ~ class_name (); | (2) | |
decl-specifier-seq(optional) ~ class_name () = default; | (3) | (since C++11) |
decl-specifier-seq(optional) ~ class_name () = delete; | (4) | (since C++11) |
attr(optional) decl-specifier-seq(optional) id-expression ( void (optional) ) except(optional) attr(optional) ; | (5) |
decl-specifier-seq | - | friend , inline , virtual , or nothing (no return type) |
||
id-expression | - | within a class definition, the symbol ~ followed by the class name. Within a class template, the symbol ~ followed by the name of the current instantiation of the template. At namespace scope or in a friend declaration within a different class, nested-name-specifier followed by the symbol ~ followed by the class name which is the same class as the one named by the nested-name-specifier. In any case, the name must be the actual name of the class or template, and not a typedef. The entire id-expression may be surrounded by parentheses which do not change its meaning. |
||
attr(C++11) | - | optional sequence of any number of attributes | ||
except | - | exception specification as in any function declaration (either dynamic exception specification(deprecated) or noexcept specification(C++11))
|
The destructor is called whenever an object's lifetime ends, which includes.
| (since C++11) |
The destructor may also be called directly, e.g. to destroy an object that was constructed using placement-new or through an allocator member function such as std::allocator::destroy(), to destroy an object that was constructed through the allocator. Note that calling a destructor directly for an ordinary object, such as a local variable, invokes undefined behavior when the destructor is called again, at the end of scope.
In generic contexts, the destructor call syntax can be used with an object of non-class type; this is known as pseudo-destructor call: see member access operator.
If no user-declared destructor is provided for a class type (struct
, class
, or union
), the compiler will always declare a destructor as an inline public
member of its class.
As with any implicitly-declared special member function, the exception specification of the implicitly-declared destructor is non-throwing unless the destructor of any potentially-constructed base or member is potentially-throwing (since C++17)implicit definition would directly invoke a function with a different exception specification (until C++17). In practice, implicit destructors are noexcept
unless the class is "poisoned" by a base or member whose destructor is noexcept(false)
.
The implicitly-declared or defaulted destructor for class T
is undefined (until C++11)defined as deleted (since C++11) if any of the following is true:
T
has a non-static data member that cannot be destructed (has deleted or inaccessible destructor) T
has direct or virtual base class that cannot be destructed (has deleted or inaccessible destructors)
| (since C++11) |
operator delete()
results in a call to ambiguous, deleted, or inaccessible function. The destructor for class T
is trivial if all of the following is true:
A trivial destructor is a destructor that performs no action. Objects with trivial destructors don't require a delete-expression and may be disposed of by simply deallocating their storage. All data types compatible with the C language (POD types) are trivially destructible.
If an implicitly-declared destructor is not deleted, it is implicitly defined (that is, a function body is generated and compiled) by the compiler when it is odr-used. This implicitly-defined destructor has an empty body.
For both user-defined or implicitly-defined destructors, after the body of the destructor is executed, the compiler calls the destructors for all non-static non-variant members of the class, in reverse order of declaration, then it calls the destructors of all direct non-virtual base classes in reverse order of construction (which in turn call the destructors of their members and their base classes, etc), and then, if this object is of most-derived class, it calls the destructors of all virtual bases.
Even when the destructor is called directly (e.g. obj.~Foo();
), the return statement in ~Foo()
does not return control to the caller immediately: it calls all those member and base destructors first.
Deleting an object through pointer to base invokes undefined behavior unless the destructor in the base class is virtual:
class Base { public: virtual ~Base() {} }; class Derived : public Base {}; Base* b = new Derived; delete b; // safe
A common guideline is that a destructor for a base class must be either public and virtual or protected and nonvirtual.
A destructor may be declared pure virtual, for example in a base class which needs to be made abstract, but has no other suitable functions that could be declared pure virtual. Such destructor must have a definition, since all base class destructors are always called when the derived class is destroyed:
class AbstractBase { public: virtual ~AbstractBase() = 0; }; AbstractBase::~AbstractBase() {} class Derived : public AbstractBase {}; // AbstractBase obj; // compiler error Derived obj; // OK
As any other function, a destructor may terminate by throwing an exception (this usually requires it to be explicitly declared noexcept(false)
) (since C++11), however if this destructor happens to be called during stack unwinding, std::terminate
is called instead.
Although std::uncaught_exception
may sometimes be used to detect stack unwinding in progress, it is generally considered bad practice to allow any destructor to terminate by throwing an exception. This functionality is nevertheless used by some libraries, such as SOCI and Galera 3, which rely on the ability of the destructors of nameless temporaries to throw exceptions at the end of the full expression that constructs the temporary.
#include <iostream> struct A { int i; A ( int i ) : i ( i ) {} ~A() { std::cout << "~a" << i << std::endl; } }; int main() { A a1(1); A* p; { // nested scope A a2(2); p = new A(3); } // a2 out of scope delete p; // calls the destructor of a3 }
Output:
~a2 ~a3 ~a1
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
http://en.cppreference.com/w/cpp/language/destructor