[class.dtor] (original) (raw)
11 Classes [class]
11.4 Class members [class.mem]
11.4.6 Destructors [class.dtor]
A prospective destructor shall take no arguments ([dcl.fct]).
Each decl-specifier of the decl-specifier-seqof a prospective destructor declaration (if any) shall befriend,inline,virtual,constexpr, orconsteval.
If a class has no user-declared prospective destructor, a prospective destructor is implicitly declared as defaulted ([dcl.fct.def]).
An implicitly-declared prospective destructor is an inline public member of its class.
An implicitly-declared prospective destructor for a class X will have the form
~X()
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 for the class, also known as the selected destructor.
The program is ill-formed if overload resolution fails.
Destructor selection does not constitute a reference to, or odr-use ([basic.def.odr]) of, the selected destructor, and in particular, the selected destructor may be deleted ([dcl.fct.def.delete]).
The address of a destructor shall not be taken.
A destructor can be invoked for aconst,volatileorconst volatileobject.
constandvolatilesemantics ([dcl.type.cv]) are not applied on an object under destruction.
They stop being in effect when the destructor for the most derived object ([intro.object]) starts.
[ Note
:
A declaration of a destructor that does not have a noexcept-specifierhas the same exception specification as if it had been implicitly declared ([except.spec]).
— end note
]
A defaulted destructor for a classX is defined as deleted if:
- X is a union-like class that has a variant member with a non-trivial destructor,
- any potentially constructed subobject has class typeM (or array thereof) andM has a deleted destructor or a destructor that is inaccessible from the defaulted destructor,
- or, 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.
A destructor is trivial if it is not user-provided and if:
- the destructor is not virtual,
- all of the direct base classes of its class have trivial destructors, and
- for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial destructor.
Otherwise, the destructor isnon-trivial.
A defaulted destructor is a constexpr destructor if it satisfies the requirements for a constexpr destructor ([dcl.constexpr]).
A destructor that is defaulted and not defined as deleted isimplicitly definedwhen it is odr-used ([basic.def.odr]) or when it is explicitly defaulted after its first declaration.
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.
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.
If a class has a base class with a virtual destructor, its destructor (whether user- or implicitly-declared) is virtual.
[ Note
:
Some language constructs have special semantics when used during destruction; see [class.cdtor].
— end note
]
After executing the body of the destructor and destroying any objects with automatic storage duration allocated within the body, a destructor for classXcalls the destructors forX's direct non-variant non-static data members, the destructors forX's non-virtual direct base classes and, ifXis the most derived class ([class.base.init]), its destructor calls the destructors forX's virtual base classes.
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.
Bases and members are destroyed in the reverse order of the completion of their constructor (see [class.base.init]).
Areturnstatement ([stmt.return]) 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.
Destructors for elements of an array are called in reverse order of their construction (see [class.init]).
A destructor is invoked implicitly
- for a constructed object with static storage duration ([basic.stc.static]) at program termination ([basic.start.term]),
- for a constructed object with thread storage duration ([basic.stc.thread]) at thread exit,
- for a constructed object with automatic storage duration ([basic.stc.auto]) when the block in which an object is created exits ([stmt.dcl]),
- for a constructed temporary object when its lifetime ends ([conv.rval], [class.temporary]).
In each case, the context of the invocation is the context of the construction of the object.
[ Note
:
An array of class type contains several subobjects for each of which the destructor is invoked.
— end note
]
A destructor can also be invoked explicitly.
A program is ill-formed if a destructor that is potentially invoked is deleted or not accessible from the context of the invocation.
At the point of definition of a virtual destructor (including an implicit definition ([class.dtor])), 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]).
If the lookup fails or if the deallocation function has a deleted definition ([dcl.fct.def]), the program is ill-formed.
[ Note
:
This assures that a deallocation function corresponding to the dynamic type of an object is available for thedelete-expression ([class.free]).
— end note
]
In an explicit destructor call, the destructor is specified by a~followed by atype-name or decltype-specifierthat denotes the destructor's class type.
The invocation of a destructor is subject to the usual rules for member functions ([class.mfct]); 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.
[ Note
:
Invoking delete on a null pointer does not call the destructor; see [expr.delete].
— end note
]
[ Example
:
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();B();
B_ptr->
B_ptr->B_alias();B();
B_ptr->B_alias::
B_ptr->B_alias::~B_alias();
}
— end example
]
[ Note
:
Explicit calls of destructors are rarely needed.
One use of such calls is for objects placed at specific addresses using a placementnew-expression.
Such use of explicit placement and destruction of objects can be necessary to cope with dedicated hardware resources and for writing memory management facilities.
For example,
void* operator new(std::size_t, void* p) { return p; } struct X { X(int); ~X(); }; void f(X* p);
void g() {
char* buf = new char[sizeof(X)];
X* p = new(buf) X(222);
f(p);
p->X::~X();
}
— end note
]
Once a destructor is invoked for an object, the object no longer exists; the behavior is undefined if the destructor is invoked for an object whose lifetime has ended ([basic.life]).
[ Example
:
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.
— end example
]
[ Note
:
The notation for explicit call of a destructor can be used for any scalar type name ([expr.prim.id.dtor]).
Allowing this makes it possible to write code without having to know if a destructor exists for a given type.
For example:
typedef int I; I* p; p->I::~I();
— end note
]
A destructor shall not be a coroutine.