This commit is contained in:
2025-10-25 03:02:53 +03:00
commit 043225d523
3416 changed files with 681196 additions and 0 deletions

389
cppdraft/class/dtor.md Normal file
View File

@@ -0,0 +1,389 @@
[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)