Skip to content

Move [class.free] #5230

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions source/basic.tex
Original file line number Diff line number Diff line change
Expand Up @@ -3810,10 +3810,13 @@
\grammarterm{new-expression}{s}\iref{expr.new}, and destroyed using
\indextext{\idxcode{delete}}%
\grammarterm{delete-expression}{s}\iref{expr.delete}. A \Cpp{} implementation
provides access to, and management of, dynamic storage via the global
\defn{allocation functions} \tcode{\keyword{operator} \keyword{new}} and \tcode{\keyword{operator}
\keyword{new}[]} and the global \defn{deallocation functions} \tcode{\keyword{operator}
\keyword{delete}} and \tcode{\keyword{operator} \keyword{delete}[]}.
provides access to, and management of, dynamic storage via
the global \defnx{allocation functions}{allocation function}
\tcode{\keyword{operator} \keyword{new}} and
\tcode{\keyword{operator} \keyword{new}[]} and
the global \defnx{deallocation functions}{deallocation function}
\tcode{\keyword{operator} \keyword{delete}} and
\tcode{\keyword{operator} \keyword{delete}[]}.
\begin{note}
The non-allocating forms described in \ref{new.delete.placement}
do not perform allocation or deallocation.
Expand Down
284 changes: 143 additions & 141 deletions source/classes.tex
Original file line number Diff line number Diff line change
Expand Up @@ -2864,6 +2864,149 @@
\end{codeblock}
\end{example}

\rSec2[class.free]{Allocation and deallocation functions}%
\indextext{free store}%

\pnum
\indextext{\idxcode{new}!type of}%
\indextext{allocation function!class-specific}%
Any allocation function for a class
\tcode{T}
is a static member (even if not explicitly declared
\keyword{static}).

\pnum
\begin{example}
\begin{codeblock}
class Arena;
struct B {
void* operator new(std::size_t, Arena*);
};
struct D1 : B {
};

Arena* ap;
void foo(int i) {
new (ap) D1; // calls \tcode{B::operator new(std::size_t, Arena*)}
new D1[i]; // calls \tcode{::operator new[](std::size_t)}
new D1; // error: \tcode{::operator new(std::size_t)} hidden
}
\end{codeblock}
\end{example}

\pnum
\indextext{\idxcode{delete}!type of}%
\indextext{deallocation function!class-specific}%
Any deallocation function for a class
\tcode{X}
is a static member (even if not explicitly declared
\keyword{static}).
\begin{example}
\begin{codeblock}
class X {
void operator delete(void*);
void operator delete[](void*, std::size_t);
};

class Y {
void operator delete(void*, std::size_t);
void operator delete[](void*);
};
\end{codeblock}
\end{example}

\pnum
Since member allocation and deallocation functions are
\keyword{static}
they cannot be virtual.
\begin{note}
However, when the
\grammarterm{cast-expression}
of a
\grammarterm{delete-expression}
refers to an object of class type with a virtual destructor,
because the deallocation function is chosen by the destructor
of the dynamic type of the object, the effect is the same in that case.
For example,
\begin{codeblock}
struct B {
virtual ~B();
void operator delete(void*, std::size_t);
};

struct D : B {
void operator delete(void*);
};

struct E : B {
void log_deletion();
void operator delete(E *p, std::destroying_delete_t) {
p->log_deletion();
p->~E();
::operator delete(p);
}
};

void f() {
B* bp = new D;
delete bp; // 1: uses \tcode{D::operator delete(void*)}
bp = new E;
delete bp; // 2: uses \tcode{E::operator delete(E*, std::destroying_delete_t)}
}
\end{codeblock}
Here, storage for the object of class
\tcode{D}
is deallocated by
\tcode{D::operator delete()},
and
the object of class \tcode{E} is destroyed
and its storage is deallocated
by \tcode{E::operator delete()},
due to the virtual destructor.
\end{note}
\begin{note}
Virtual destructors have no effect on the deallocation function actually
called when the
\grammarterm{cast-expression}
of a
\grammarterm{delete-expression}
refers to an array of objects of class type.
For example,
\begin{codeblock}
struct B {
virtual ~B();
void operator delete[](void*, std::size_t);
};

struct D : B {
void operator delete[](void*, std::size_t);
};

void f(int i) {
D* dp = new D[i];
delete [] dp; // uses \tcode{D::operator delete[](void*, std::size_t)}
B* bp = new D[i];
delete[] bp; // undefined behavior
}
\end{codeblock}
\end{note}

\pnum
Access to the deallocation function is checked statically,
even if a different one is actually executed.
\begin{example}
For the call on line ``// 1'' above,
if
\tcode{B::operator delete()}
had been private, the delete expression would have been ill-formed.
\end{example}

\pnum
\begin{note}
If a deallocation function has no explicit \grammarterm{noexcept-specifier}, it
has a non-throwing exception specification\iref{except.spec}.
\end{note}

\rSec2[class.nest]{Nested class declarations}%
\indextext{definition!nested class}%

Expand Down Expand Up @@ -6634,145 +6777,4 @@
\end{codeblock}
\end{example}

\rSec1[class.free]{Free store}%
\indextext{free store}%

\pnum
\indextext{\idxcode{new}!type of}
Any allocation function for a class
\tcode{T}
is a static member (even if not explicitly declared
\keyword{static}).

\pnum
\begin{example}
\begin{codeblock}
class Arena;
struct B {
void* operator new(std::size_t, Arena*);
};
struct D1 : B {
};

Arena* ap;
void foo(int i) {
new (ap) D1; // calls \tcode{B::operator new(std::size_t, Arena*)}
new D1[i]; // calls \tcode{::operator new[](std::size_t)}
new D1; // error: \tcode{::operator new(std::size_t)} hidden
}
\end{codeblock}
\end{example}

\pnum
\indextext{\idxcode{delete}!type of}%
Any deallocation function for a class
\tcode{X}
is a static member (even if not explicitly declared
\keyword{static}).
\begin{example}
\begin{codeblock}
class X {
void operator delete(void*);
void operator delete[](void*, std::size_t);
};

class Y {
void operator delete(void*, std::size_t);
void operator delete[](void*);
};
\end{codeblock}
\end{example}

\pnum
Since member allocation and deallocation functions are
\keyword{static}
they cannot be virtual.
\begin{note}
However, when the
\grammarterm{cast-expression}
of a
\grammarterm{delete-expression}
refers to an object of class type with a virtual destructor,
because the deallocation function is chosen by the destructor
of the dynamic type of the object, the effect is the same in that case.
For example,
\begin{codeblock}
struct B {
virtual ~B();
void operator delete(void*, std::size_t);
};

struct D : B {
void operator delete(void*);
};

struct E : B {
void log_deletion();
void operator delete(E *p, std::destroying_delete_t) {
p->log_deletion();
p->~E();
::operator delete(p);
}
};

void f() {
B* bp = new D;
delete bp; // 1: uses \tcode{D::operator delete(void*)}
bp = new E;
delete bp; // 2: uses \tcode{E::operator delete(E*, std::destroying_delete_t)}
}
\end{codeblock}
Here, storage for the object of class
\tcode{D}
is deallocated by
\tcode{D::operator delete()},
and
the object of class \tcode{E} is destroyed
and its storage is deallocated
by \tcode{E::operator delete()},
due to the virtual destructor.
\end{note}
\begin{note}
Virtual destructors have no effect on the deallocation function actually
called when the
\grammarterm{cast-expression}
of a
\grammarterm{delete-expression}
refers to an array of objects of class type.
For example,
\begin{codeblock}
struct B {
virtual ~B();
void operator delete[](void*, std::size_t);
};

struct D : B {
void operator delete[](void*, std::size_t);
};

void f(int i) {
D* dp = new D[i];
delete [] dp; // uses \tcode{D::operator delete[](void*, std::size_t)}
B* bp = new D[i];
delete[] bp; // undefined behavior
}
\end{codeblock}
\end{note}

\pnum
Access to the deallocation function is checked statically,
even if a different one is actually executed.
\begin{example}
For the call on line ``// 1'' above,
if
\tcode{B::operator delete()}
had been private, the delete expression would have been ill-formed.
\end{example}

\pnum
\begin{note}
If a deallocation function has no explicit \grammarterm{noexcept-specifier}, it
has a non-throwing exception specification\iref{except.spec}.
\end{note}

\indextext{class|)}