[class.dtor] # 11 Classes [[class]](./#class) ## 11.4 Class members [[class.mem]](class.mem#class.dtor) ### 11.4.7 Destructors [class.dtor] [1](#1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L2082) A declaration whose [*declarator-id*](dcl.decl.general#nt:declarator-id "9.3.1 General [dcl.decl.general]") has an [*unqualified-id*](expr.prim.id.unqual#nt:unqualified-id "7.5.5.2 Unqualified names [expr.prim.id.unqual]") that begins with a ~ declares a [*prospective destructor*](#def:destructor,prospective "11.4.7 Destructors [class.dtor]"); its [*declarator*](dcl.decl.general#nt:declarator "9.3.1 General [dcl.decl.general]") shall be a function declarator ([[dcl.fct]](dcl.fct "9.3.4.6 Functions")) of the form [*ptr-declarator*](dcl.decl.general#nt:ptr-declarator "9.3.1 General [dcl.decl.general]") ( [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") ) [*noexcept-specifier*](except.spec#nt:noexcept-specifier "14.5 Exception specifications [except.spec]")opt [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt where the [*ptr-declarator*](dcl.decl.general#nt:ptr-declarator "9.3.1 General [dcl.decl.general]") consists solely of an[*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]"), an optional [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]"), and optional surrounding parentheses, and the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") has one of the following forms: - [(1.1)](#1.1) in a [*member-declaration*](class.mem.general#nt:member-declaration "11.4.1 General [class.mem.general]") that belongs to the[*member-specification*](class.mem.general#nt:member-specification "11.4.1 General [class.mem.general]") of a class or class template but is not a friend declaration ([[class.friend]](class.friend "11.8.4 Friends")), the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") is~[*class-name*](class.pre#nt:class-name "11.1 Preamble [class.pre]") and the [*class-name*](class.pre#nt:class-name "11.1 Preamble [class.pre]") is the injected-class-name ([[class.pre]](class.pre "11.1 Preamble")) of the immediately-enclosing entity or - [(1.2)](#1.2) otherwise, the[*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") is [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")~[*class-name*](class.pre#nt:class-name "11.1 Preamble [class.pre]") and the [*class-name*](class.pre#nt:class-name "11.1 Preamble [class.pre]") is the injected-class-name of the class nominated by the [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]")[.](#1.sentence-1) A prospective destructor shall take no arguments ([[dcl.fct]](dcl.fct "9.3.4.6 Functions"))[.](#1.sentence-2) Each [*decl-specifier*](dcl.spec.general#nt:decl-specifier "9.2.1 General [dcl.spec.general]") of the [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") of a prospective destructor declaration (if any) shall befriend,inline,virtual, orconstexpr[.](#1.sentence-3) [2](#2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L2120) If a class has no user-declared prospective destructor, a prospective destructor is implicitly declared as defaulted ([[dcl.fct.def]](dcl.fct.def "9.6 Function definitions"))[.](#2.sentence-1) An implicitly-declared prospective destructor is an inline public member of its class[.](#2.sentence-2) [3](#3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L2130) An implicitly-declared prospective destructor for a class X will have the form~X() [4](#4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L2136) At the end of the definition of a class, overload resolution is performed among the prospective destructors declared in that class with an empty argument list to select the [*destructor*](#def:destructor "11.4.7 Destructors [class.dtor]") for the class, also known as the [*selected destructor*](#def:destructor,selected "11.4.7 Destructors [class.dtor]")[.](#4.sentence-1) The program is ill-formed if overload resolution fails[.](#4.sentence-2) Destructor selection does not constitute a reference to, or odr-use ([[basic.def.odr]](basic.def.odr#term.odr.use "6.3 One-definition rule")) of, the selected destructor, and in particular, the selected destructor may be deleted ([[dcl.fct.def.delete]](dcl.fct.def.delete "9.6.3 Deleted definitions"))[.](#4.sentence-3) [5](#5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L2151) The address of a destructor shall not be taken[.](#5.sentence-1) [*Note [1](#note-1)*: A return statement in the body of a destructor cannot specify a return value ([[stmt.return]](stmt.return "8.8.4 The return statement"))[.](#5.sentence-2) — *end note*] A destructor can be invoked for aconst,volatile orconstvolatile object[.](#5.sentence-3) const andvolatile semantics ([[dcl.type.cv]](dcl.type.cv "9.2.9.2 The cv-qualifiers")) are not applied on an object under destruction[.](#5.sentence-4) They stop being in effect when the destructor for the most derived object ([[intro.object]](intro.object "6.8.2 Object model")) starts[.](#5.sentence-5) [6](#6) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L2175) [*Note [2](#note-2)*: A declaration of a destructor that does not have a [*noexcept-specifier*](except.spec#nt:noexcept-specifier "14.5 Exception specifications [except.spec]") has the same exception specification as if it had been implicitly declared ([[except.spec]](except.spec "14.5 Exception specifications"))[.](#6.sentence-1) — *end note*] [7](#7) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L2181) A defaulted destructor for a class X is defined as deleted if - [(7.1)](#7.1) X is a non-union class and any non-variant potentially constructed subobject has class type M (or possibly multidimensional array thereof) where M has a destructor that is deleted or is inaccessible from the defaulted destructor, - [(7.2)](#7.2) X is a union and * [(7.2.1)](#7.2.1) overload resolution to select a constructor to default-initialize an object of type X either fails or selects a constructor that is either deleted or not trivial, or * [(7.2.2)](#7.2.2) X has a variant member V of class type M (or possibly multi-dimensional array thereof) where V has a default member initializer and M has a destructor that is non-trivial, or, - [(7.3)](#7.3) for a virtual destructor, lookup of the non-array deallocation function results in an ambiguity or in a function that is deleted or inaccessible from the defaulted destructor[.](#7.sentence-1) [8](#8) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L2210) A destructor for a class X is trivial if it is not user-provided and if - [(8.1)](#8.1) the destructor is not virtual, - [(8.2)](#8.2) all of the direct base classes of X have trivial destructors, and - [(8.3)](#8.3) either X is a union or for all of the non-variant non-static data members of X that are of class type (or array thereof), each such class has a trivial destructor[.](#8.sentence-1) Otherwise, the destructor is[*non-trivial*](#def:destructor,non-trivial "11.4.7 Destructors [class.dtor]")[.](#8.sentence-2) [9](#9) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L2225) A defaulted destructor is a constexpr destructor if it is constexpr-suitable ([[dcl.constexpr]](dcl.constexpr "9.2.6 The constexpr and consteval specifiers"))[.](#9.sentence-1) [10](#10) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L2229) Before a defaulted destructor for a class is implicitly defined, all the non-user-provided destructors for its base classes and its non-static data members are implicitly defined[.](#10.sentence-1) [11](#11) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L2235) A prospective destructor can be declared virtual ([[class.virtual]](class.virtual "11.7.3 Virtual functions")) and with a [*pure-specifier*](class.mem.general#nt:pure-specifier "11.4.1 General [class.mem.general]") ([[class.abstract]](class.abstract "11.7.4 Abstract classes"))[.](#11.sentence-1) If the destructor of a class is virtual and any objects of that class or any derived class are created in the program, the destructor shall be defined[.](#11.sentence-2) [12](#12) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L2245) [*Note [3](#note-3)*: Some language constructs have special semantics when used during destruction; see [[class.cdtor]](class.cdtor "11.9.5 Construction and destruction")[.](#12.sentence-1) — *end note*] [13](#13) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L2252) After executing the body of the destructor and destroying any objects with automatic storage duration allocated within the body, a destructor for classX calls the destructors forX's direct non-variant non-static data members other than anonymous unions, the destructors forX's non-virtual direct base classes and, ifX is the most derived class ([[class.base.init]](class.base.init "11.9.3 Initializing bases and members")), its destructor calls the destructors forX's virtual base classes[.](#13.sentence-1) All destructors are called as if they were referenced with a qualified name, that is, ignoring any possible virtual overriding destructors in more derived classes[.](#13.sentence-2) Bases and members are destroyed in the reverse order of the completion of their constructor (see [[class.base.init]](class.base.init "11.9.3 Initializing bases and members"))[.](#13.sentence-3) [*Note [4](#note-4)*: Areturn statement ([[stmt.return]](stmt.return "8.8.4 The return statement")) in a destructor might not directly return to the caller; before transferring control to the caller, the destructors for the members and bases are called[.](#13.sentence-4) — *end note*] Destructors for elements of an array are called in reverse order of their construction (see [[class.init]](class.init "11.9 Initialization"))[.](#13.sentence-5) [14](#14) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L2287) A destructor is invoked implicitly - [(14.1)](#14.1) for a constructed object with static storage duration ([[basic.stc.static]](basic.stc.static "6.8.6.2 Static storage duration")) at program termination ([[basic.start.term]](basic.start.term "6.10.3.4 Termination")), - [(14.2)](#14.2) for a constructed object with thread storage duration ([[basic.stc.thread]](basic.stc.thread "6.8.6.3 Thread storage duration")) at thread exit, - [(14.3)](#14.3) for a constructed object with automatic storage duration ([[basic.stc.auto]](basic.stc.auto "6.8.6.4 Automatic storage duration")) when the block in which an object is created exits ([[stmt.dcl]](stmt.dcl "8.10 Declaration statement")), - [(14.4)](#14.4) for a constructed temporary object when its lifetime ends ([[conv.rval]](conv.rval "7.3.5 Temporary materialization conversion"), [[class.temporary]](class.temporary "6.8.7 Temporary objects"))[.](#14.sentence-1) In each case, the context of the invocation is the context of the construction of the object[.](#14.sentence-2) A destructor may also be invoked implicitly through use of a[*delete-expression*](expr.delete#nt:delete-expression "7.6.2.9 Delete [expr.delete]") ([[expr.delete]](expr.delete "7.6.2.9 Delete")) for a constructed object allocated by a [*new-expression*](expr.new#nt:new-expression "7.6.2.8 New [expr.new]") ([[expr.new]](expr.new "7.6.2.8 New")); the context of the invocation is the[*delete-expression*](expr.delete#nt:delete-expression "7.6.2.9 Delete [expr.delete]")[.](#14.sentence-3) [*Note [5](#note-5)*: An array of class type contains several subobjects for each of which the destructor is invoked[.](#14.sentence-4) — *end note*] A destructor can also be invoked explicitly[.](#14.sentence-5) A destructor is [*potentially invoked*](#def:potentially_invoked "11.4.7 Destructors [class.dtor]") if it is invoked or as specified in [[expr.new]](expr.new "7.6.2.8 New"),[[stmt.return]](stmt.return "8.8.4 The return statement"), [[dcl.init.aggr]](dcl.init.aggr "9.5.2 Aggregates"),[[class.base.init]](class.base.init "11.9.3 Initializing bases and members"), and [[except.throw]](except.throw "14.2 Throwing an exception")[.](#14.sentence-6) A program is ill-formed if a destructor that is potentially invoked is deleted or not accessible from the context of the invocation[.](#14.sentence-7) [15](#15) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L2319) At the point of definition of a virtual destructor (including an implicit definition), the non-array deallocation function is determined as if for the expression delete this appearing in a non-virtual destructor of the destructor's class (see [[expr.delete]](expr.delete "7.6.2.9 Delete"))[.](#15.sentence-1) If the lookup fails or if the deallocation function has a deleted definition ([[dcl.fct.def]](dcl.fct.def "9.6 Function definitions")), the program is ill-formed[.](#15.sentence-2) [*Note [6](#note-6)*: This assures that a deallocation function corresponding to the dynamic type of an object is available for the[*delete-expression*](expr.delete#nt:delete-expression "7.6.2.9 Delete [expr.delete]") ([[class.free]](class.free "11.4.11 Allocation and deallocation functions"))[.](#15.sentence-3) — *end note*] [16](#16) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L2332) In an explicit destructor call, the destructor is specified by a~ followed by a[*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]") or [*computed-type-specifier*](dcl.type.simple#nt:computed-type-specifier "9.2.9.3 Simple type specifiers [dcl.type.simple]") that denotes the destructor's class type[.](#16.sentence-1) The invocation of a destructor is subject to the usual rules for member functions ([[class.mfct]](class.mfct "11.4.2 Member functions")); 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[.](#16.sentence-2) [*Note [7](#note-7)*: Invoking delete on a null pointer does not call the destructor; see [[expr.delete]](expr.delete "7.6.2.9 Delete")[.](#16.sentence-3) — *end note*] [*Example [1](#example-1)*: struct B {virtual ~B() { }};struct D : B {~D() { }}; D D_object;typedef B B_alias; B* B_ptr = &D_object; void f() { D_object.B::~B(); // calls B's destructor B_ptr->~B(); // calls D's destructor B_ptr->~B_alias(); // calls D's destructor B_ptr->B_alias::~B(); // calls B's destructor B_ptr->B_alias::~B_alias(); // calls B's destructor} — *end example*] [*Note [8](#note-8)*: An explicit destructor call must always be written using a member access operator ([[expr.ref]](expr.ref "7.6.1.5 Class member access")) or a [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") ([[expr.prim.id.qual]](expr.prim.id.qual "7.5.5.3 Qualified names")); in particular, the[*unary-expression*](expr.unary.general#nt:unary-expression "7.6.2.1 General [expr.unary.general]")~X() in a member function is not an explicit destructor call ([[expr.unary.op]](expr.unary.op "7.6.2.2 Unary operators"))[.](#16.sentence-4) — *end note*] [17](#17) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L2380) [*Note [9](#note-9)*: Explicit calls of destructors are rarely needed[.](#17.sentence-1) One use of such calls is for objects placed at specific addresses using a placement[*new-expression*](expr.new#nt:new-expression "7.6.2.8 New [expr.new]")[.](#17.sentence-2) Such use of explicit placement and destruction of objects can be necessary to cope with dedicated hardware resources and for writing memory management facilities[.](#17.sentence-3) [*Example [2](#example-2)*: void* operator new(std::size_t, void* p) { return p; }struct X { X(int); ~X();};void f(X* p); void g() { // rare, specialized use:char* buf = new char[sizeof(X)]; X* p = new(buf) X(222); // use buf[] and initialize f(p); p->X::~X(); // cleanup} — *end example*] — *end note*] [18](#18) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L2409) Once a destructor is invoked for an object, the object's lifetime ends; the behavior is undefined if the destructor is invoked for an object whose lifetime has ended ([[basic.life]](basic.life "6.8.4 Lifetime"))[.](#18.sentence-1) [*Example [3](#example-3)*: If the destructor for an object with automatic storage duration 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[.](#18.sentence-2) — *end example*] [19](#19) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L2419) [*Note [10](#note-10)*: The notation for explicit call of a destructor can be used for any scalar type name ([[expr.prim.id.dtor]](expr.prim.id.dtor "7.5.5.5 Destruction"))[.](#19.sentence-1) Allowing this makes it possible to write code without having to know if a destructor exists for a given type[.](#19.sentence-2) For example:typedef int I; I* p; p->I::~I(); — *end note*] [20](#20) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L2434) A destructor shall not be a coroutine[.](#20.sentence-1)