A destructor is a special
that is called when the
ends. The purpose of the destructor is to free the resources that the object may have acquired during its lifetime.
A destructor cannot be a
.
(since C++20)Syntax
Destructors(until C++20)
(since C++20) are declared using member
of the following form:
class-name-with-tilde(parameter-list(optional))except(optional)attr(optional)The only specifiers allowed in the
of a prospective(since C++20) destructor declaration are
,(since C++11)
,
and
(in particular, no return type is allowed).
The identifier expression of class-name-with-tilde must have one of the following forms:
In a member declaration that belongs to the
of a class or class template, but is not a
:
For classes, the identifier expression is ~ followed by the
of the immediately-enclosing class.
For class templates, the identifier expression is ~ followed by a class name that names the
(until C++20)the injected-class-name(since C++20) of the immediately-enclosing class template.
Otherwise, the identifier expression is a qualified identifier whose terminal unqualified identifier is ~ followed by the injected-class name of the class nominated by the non-terminal parts of the qualified identifier.
Explanation
The destructor is implicitly invoked whenever an object's
ends, which includes
, for objects with static
thread exit, for objects with thread-local storage duration
(since C++11)end of scope, for objects with automatic storage duration and for temporaries whose life was extended by binding to a reference
, for objects with dynamic storage duration
end of the full
, for nameless temporaries
, for objects with automatic storage duration when an exception escapes their block, uncaught.
The destructor can also be invoked explicitly.
Prospective destructor
A class may have one or more prospective destructors, one of which is selected as the destructor for the class.
In order to determine which prospective destructor is the destructor, at the end of the definition of the class,
is performed among prospective destructors declared in the class with an empty argument list. If the overload resolution fails, the program is ill-formed. Destructor selection does not
the selected destructor, and the selected destructor may be deleted.
All prospective destructors are special member functions. If no user-declared prospective destructor is provided for class T, the compiler will always
one, and the implicitly-declared prospective destructor is also the destructor for T.
Run this code
#include<cstdio>#include<type_traits>template<typenameT>structA{~A()requiresstd::is_integral_v<T>{std::puts("~A, T is integral");}~A()requiresstd::is_pointer_v<T>{std::puts("~A, T is a pointer");}~A(){std::puts("~A, T is anything else");}};intmain(){A<int>a;A<int*>b;A<float>c;}Output:
~A, T is anything else ~A, T is a pointer ~A, T is integral (since C++20)Potentially-invoked destructor
The destructor for class T is potentially invoked in the following situations:
It is invoked explicitly or implicitly.
A
creates an array of objects of type T.
The result object of a
is of type T.
An array is under
, and its element type is T.
A class object is under aggregate initialization, and it has a member of type T where T is not an
type.
A
potentially constructed subobject
is of type T in a non-
(since C++11) constructor.
An
of type T is constructed.
If a potentially-invoked destructor is deleted or(since C++11) not accessible from the context of the invocation, the program is ill-formed.
Implicitly-declared destructor
If no user-declared prospective(since C++20) destructor is provided for a
, the compiler will always declare a destructor as an inlinepublic 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
(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).
Implicitly-defined destructor
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
. This implicitly-defined destructor has an empty body.
Deleted destructor
The implicitly-declared or explicitly-defaulted destructor for class T is defined as deleted if any of the following conditions is satisfied:
T has a
potentially constructed subobject
of class type M (or possibly multi-dimensional array thereof) such that M has a destructor that
is deleted or inaccessible from the destructor of T, or
in the case of the subobject being a
, is non-trivial.
(until C++26)T is not a union, and has a non-
potentially constructed subobject
of class type M (or possibly multidimensional array thereof) such that M has a destructor that is deleted or inaccessible from the destructor of T.
T is a union, and any of the following conditions is satisfied:
The overload resolution to select a constructor to default-initialize an object of type T either fails or selects a constructor that is either deleted or non-trivial.
T has a variant member V of class type M (or possibly multidimensional array thereof) where V has a default initializer and M has a destructor that is non-trivial.
(since C++26)The destructor is virtual and the lookup for the
results in
an ambiguity, or
a function that is deleted or inaccessible from the destructor.
An explicitly-defaulted prospective destructor for T is defined as deleted if it is not the destructor for T.
(since C++20)(since C++11)Trivial destructor
The destructor for class T is trivial if all following conditions are satisfied:
The destructor is implicitly-declared(until C++11)not
(since C++11).
The destructor is not virtual.
All direct base classes have trivial destructors.
Every non-static data member of class type (or array of class type) has a trivial destructor.
(until C++26)Either T is a union, or every non-variant non-static data member of class type (or array of class type) has a trivial destructor.
(since C++26)A trivial destructor is a destructor that performs no action. An object with a trivial destructor may safely end its lifetime without invoking its destructor (for example, by deallocating the storage for the object) without risk of resource leaks. Destroying an object with a non-trivial destructor without calling its destructor is not undefined behavior, but the correct operation of the program typically relies on that destructor. All data types compatible with the C language (POD types) are trivially destructible.
Destruction sequence
For both user-defined or implicitly-defined destructors, after executing the body of the destructor and destroying any automatic objects allocated within the body, the compiler calls the destructors for all non-static non-variant data members of the class, in reverse order of declaration, then it calls the destructors of all direct non-virtual base classes in
(which in turn call the destructors of their members and their base classes, etc), and then, if this object is of
, 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.
Virtual destructors
Deleting a derived object through pointer to base invokes undefined behavior unless the destructor in the base class is
:
classBase{public:virtual~Base(){}};classDerived:publicBase{};Base*b=newDerived;deleteb;// safeA common guideline is that a destructor for a base class must be
either public and virtual or protected and nonvirtual
.
Pure virtual destructors
A prospective(since C++20) destructor may be declared
, for example in a base class which needs to be made abstract, but has no other suitable functions that could be declared pure virtual. A pure virtual destructor must have a definition, since all base class destructors are always called when the derived class is destroyed:
classAbstractBase{public:virtual~AbstractBase()=0;};AbstractBase::~AbstractBase(){}classDerived:publicAbstractBase{};// AbstractBase obj; // compiler errorDerivedobj;// OKExceptions
As any other function, a destructor may terminate by throwing an
(this usually requires it to be explicitly declared noexcept(false))(since C++11), however if this destructor happens to be called during
,
is called instead.
Although
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
and
, 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.
std::experimental::scope_success
in Library fundamental TS v3 may have
a potentially-throwing destructor
, which throws an exception when the scope is exited normally and the exit function throws an exception.
Notes
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
.
Feature-test macroValueStdFeature
(C++26)Relaxing the triviality requirements for special member functions of unions Example
Run this code
#include<iostream>structA{inti;A(intnum):i(num){std::cout<<"ctor a"<<i<<'\n';}(~A)()// but usually ~A(){std::cout<<"dtor a"<<i<<'\n';}};Aa0(0);intmain(){Aa1(1);A*p;{// nested scopeAa2(2);p=newA(3);}// a2 out of scopedeletep;// calls the destructor of a3}Output:
ctor a0 ctor a1 ctor a2 ctor a3 dtor a2 dtor a3 dtor a1 dtor a0 Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR Applied to Behavior as published Correct behavior
C++98 whether automatic objects in a destructor are
destroyed before or after the destruction of the
class's base and member subobjects was unspecified they are destroyed
before destroying
those subobjects
C++98 the declarator syntax of destructor was defective (had the
same problem as
and
changed the syntax to a specialized
function declarator syntax
C++98 static members might be destroyed
right after destructor execution only destroy non-
static members
C++98 the conditions where implicitly-declared destructors are
undefined did not consider multi-dimensional array types consider these types
C++98 the meaning of “class name” in the
declarator syntax of destructor was unclear changed the syntax to a specialized
function declarator syntax
C++98 the destructor of a class that is not a most derived class
would call the destructors of its virtual direct base classes it will not call those destructors
C++20 the declaration specifiers could contain constevalprohibited See also