Files
2025-10-25 03:02:53 +03:00

390 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[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.1General[dcl.decl.general]") has an [*unqualified-id*](expr.prim.id.unqual#nt:unqualified-id "7.5.5.2Unqualified names[expr.prim.id.unqual]") that begins with a ~ declares a [*prospective destructor*](#def:destructor,prospective "11.4.7Destructors[class.dtor]");
its [*declarator*](dcl.decl.general#nt:declarator "9.3.1General[dcl.decl.general]") shall be a function declarator ([[dcl.fct]](dcl.fct "9.3.4.6Functions")) of the form
[*ptr-declarator*](dcl.decl.general#nt:ptr-declarator "9.3.1General[dcl.decl.general]") ( [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6Functions[dcl.fct]") ) [*noexcept-specifier*](except.spec#nt:noexcept-specifier "14.5Exception specifications[except.spec]")opt [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1Attribute syntax and semantics[dcl.attr.grammar]")opt
where the [*ptr-declarator*](dcl.decl.general#nt:ptr-declarator "9.3.1General[dcl.decl.general]") consists solely of an[*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[expr.prim.id.general]"), an optional [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1Attribute syntax and semantics[dcl.attr.grammar]"),
and optional surrounding parentheses, and the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[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.1General[class.mem.general]") that belongs to the[*member-specification*](class.mem.general#nt:member-specification "11.4.1General[class.mem.general]") of a class or class template
but is not a friend
declaration ([[class.friend]](class.friend "11.8.4Friends")), the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[expr.prim.id.general]") is~[*class-name*](class.pre#nt:class-name "11.1Preamble[class.pre]") and the [*class-name*](class.pre#nt:class-name "11.1Preamble[class.pre]") is the
injected-class-name ([[class.pre]](class.pre "11.1Preamble")) of the immediately-enclosing entity or
- [(1.2)](#1.2)
otherwise, the[*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[expr.prim.id.general]") is [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3Qualified names[expr.prim.id.qual]")~[*class-name*](class.pre#nt:class-name "11.1Preamble[class.pre]") and the [*class-name*](class.pre#nt:class-name "11.1Preamble[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.3Qualified names[expr.prim.id.qual]")[.](#1.sentence-1)
A prospective destructor shall take no arguments ([[dcl.fct]](dcl.fct "9.3.4.6Functions"))[.](#1.sentence-2)
Each [*decl-specifier*](dcl.spec.general#nt:decl-specifier "9.2.1General[dcl.spec.general]") of the [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1General[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.6Function 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.7Destructors[class.dtor]") for the class,
also known as the [*selected destructor*](#def:destructor,selected "11.4.7Destructors[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.3One-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.3Deleted 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.4The 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.2The 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.2Object 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.5Exception specifications[except.spec]") has the same exception specification as if it had been implicitly declared ([[except.spec]](except.spec "14.5Exception 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.7Destructors[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.6The 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.3Virtual functions"))
and with a [*pure-specifier*](class.mem.general#nt:pure-specifier "11.4.1General[class.mem.general]") ([[class.abstract]](class.abstract "11.7.4Abstract 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.5Construction 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.3Initializing 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.3Initializing bases and members"))[.](#13.sentence-3)
[*Note [4](#note-4)*:
Areturn statement ([[stmt.return]](stmt.return "8.8.4The 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.9Initialization"))[.](#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.2Static storage duration")) at program termination ([[basic.start.term]](basic.start.term "6.10.3.4Termination")),
- [(14.2)](#14.2)
for a constructed object with thread storage duration ([[basic.stc.thread]](basic.stc.thread "6.8.6.3Thread 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.4Automatic storage duration")) when the block in which an object is created exits ([[stmt.dcl]](stmt.dcl "8.10Declaration statement")),
- [(14.4)](#14.4)
for a constructed temporary object when its lifetime ends ([[conv.rval]](conv.rval "7.3.5Temporary materialization conversion"), [[class.temporary]](class.temporary "6.8.7Temporary 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.9Delete[expr.delete]") ([[expr.delete]](expr.delete "7.6.2.9Delete")) for a constructed object allocated
by a [*new-expression*](expr.new#nt:new-expression "7.6.2.8New[expr.new]") ([[expr.new]](expr.new "7.6.2.8New")); the context of the invocation is the[*delete-expression*](expr.delete#nt:delete-expression "7.6.2.9Delete[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.7Destructors[class.dtor]") if it is invoked or as specified in [[expr.new]](expr.new "7.6.2.8New"),[[stmt.return]](stmt.return "8.8.4The return statement"), [[dcl.init.aggr]](dcl.init.aggr "9.5.2Aggregates"),[[class.base.init]](class.base.init "11.9.3Initializing bases and members"), and [[except.throw]](except.throw "14.2Throwing 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.9Delete"))[.](#15.sentence-1)
If the lookup fails or if the deallocation function has
a deleted definition ([[dcl.fct.def]](dcl.fct.def "9.6Function 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.9Delete[expr.delete]") ([[class.free]](class.free "11.4.11Allocation 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.3Simple type specifiers[dcl.type.simple]") or [*computed-type-specifier*](dcl.type.simple#nt:computed-type-specifier "9.2.9.3Simple 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.2Member 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.9Delete")[.](#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.5Class member access")) or a [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3Qualified names[expr.prim.id.qual]") ([[expr.prim.id.qual]](expr.prim.id.qual "7.5.5.3Qualified names"));
in particular, the[*unary-expression*](expr.unary.general#nt:unary-expression "7.6.2.1General[expr.unary.general]")~X() in a member function is not an explicit destructor call ([[expr.unary.op]](expr.unary.op "7.6.2.2Unary 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.8New[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.4Lifetime"))[.](#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.5Destruction"))[.](#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)