Skip to content

Suggested changes for CWG#204 (on GitHub) #6038

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
26 changes: 20 additions & 6 deletions source/basic.tex
Original file line number Diff line number Diff line change
Expand Up @@ -3432,10 +3432,7 @@
program has undefined behavior if:
\begin{itemize}
\item
the pointer is used as the operand of a \grammarterm{delete-expression},
\item
the pointer is used to access a non-static data member or call a
non-static member function of the object, or
the pointer is used as the operand of a \grammarterm{delete-expression}, or
\item
the pointer is implicitly converted\iref{conv.ptr} to a pointer
to a virtual base class, or
Expand All @@ -3451,6 +3448,10 @@
the pointer is used as the operand of a
\keyword{dynamic_cast}\iref{expr.dynamic.cast}.
\end{itemize}
\begin{note}
Referencing a non-static data member or calling a non-static member function is
performed via a glvalue formed by indirecting the pointer; see below.
\end{note}
\begin{example}
\begin{codeblock}
#include <cstdlib>
Expand All @@ -3466,7 +3467,7 @@

void B::mutate() {
new (this) D2; // reuses storage --- ends the lifetime of \tcode{*this}
f(); // undefined behavior
f(); // undefined behavior (see below)
... = this; // OK, \keyword{this} points to valid memory
}

Expand All @@ -3476,7 +3477,7 @@
pb->mutate();
*pb; // OK, \tcode{pb} points to valid memory
void* q = pb; // OK, \tcode{pb} points to valid memory
pb->f(); // undefined behavior: lifetime of \tcode{*pb} has ended
pb->f(); // undefined behavior (see below): lifetime of \tcode{*pb} has ended
}
\end{codeblock}
\end{example}
Expand All @@ -3497,10 +3498,23 @@
\item the glvalue is used to access the object, or
\item the glvalue is used to call a non-static member function of the object, or
\item the glvalue is bound to a reference to a virtual base class\iref{dcl.init.ref}, or
\item the glvalue is used to refer to a non-static data member of a virtual base class, or
\item the glvalue is used as the operand of a
\keyword{dynamic_cast}\iref{expr.dynamic.cast} or as the operand of
\keyword{typeid}.
\end{itemize}
\begin{example}
\begin{codeblock}
struct W { int j; };
struct X : public virtual W { };
struct Y {
int* p;
X x;
Y() : p(&x.j) { // undefined, x is not yet constructed
}
};
\end{codeblock}
\end{example}

\pnum
If, after the lifetime of an object has ended and before the storage
Expand Down
66 changes: 16 additions & 50 deletions source/classes.tex
Original file line number Diff line number Diff line change
Expand Up @@ -5924,44 +5924,10 @@
\indextext{destruction|(}%

\pnum
\indextext{construction!member access}%
\indextext{destruction!member access}%
For an object with a non-trivial constructor, referring to any non-static member
or base class of the object before the constructor begins execution results in
undefined behavior. For an object with a non-trivial destructor, referring to
any non-static member or base class of the object after the destructor finishes
execution results in undefined behavior.
\begin{example}
\begin{codeblock}
struct X { int i; };
struct Y : X { Y(); }; // non-trivial
struct A { int a; };
struct B : public A { int j; Y y; }; // non-trivial

extern B bobj;
B* pb = &bobj; // OK
int* p1 = &bobj.a; // undefined behavior: refers to base class member
int* p2 = &bobj.y.i; // undefined behavior: refers to member's member

A* pa = &bobj; // undefined behavior: upcast to a base class type
B bobj; // definition of \tcode{bobj}

extern X xobj;
int* p3 = &xobj.i; // OK, \tcode{X} is a trivial class
X xobj;
\end{codeblock}
For another example,
\begin{codeblock}
struct W { int j; };
struct X : public virtual W { };
struct Y {
int* p;
X x;
Y() : p(&x.j) { // undefined, \tcode{x} is not yet constructed
}
};
\end{codeblock}
\end{example}
\begin{note}
\ref{basic.life} describes how a pointer or glvalue to an object that is outside
its lifetime and is not under construction or destruction can be used.
\end{note}

\pnum
During the construction of an object,
Expand Down Expand Up @@ -6001,28 +5967,28 @@
\pnum
\indextext{construction!pointer to member or base}%
\indextext{destruction!pointer to member or base}%
\indextext{construction!member access}%
\indextext{destruction!member access}%
To explicitly or implicitly convert a pointer (a glvalue) referring to
an object of class
\tcode{X}
to a pointer (reference) to a direct or indirect base class
that is under construction or destruction
to a pointer (reference) to a direct or indirect virtual base class
\tcode{B}
of
\tcode{X},
or to use said pointer (glvalue) to form a glvalue to a non-static data member
of the \tcode{B} subobject of \tcode{obj}, or to call a non-static member
function of said object,
the construction of
\tcode{X}
and the construction of all of its direct or indirect bases that directly or
indirectly derive from
and the construction of all of its direct or indirect bases
for which
\tcode{B}
is a direct or indirect virtual base
shall have started and the destruction of these classes shall not have
completed, otherwise the conversion results in undefined behavior.
To form a pointer to (or access the value of) a direct non-static member of
an object
\tcode{obj},
the construction of
\tcode{obj}
shall have started and its destruction shall not have completed,
otherwise the computation of the pointer value (or accessing the member
value) results in undefined behavior.
completed, otherwise the conversion, member access or member function call
results in undefined behavior.
\begin{example}
\begin{codeblock}
struct A { };
Expand Down