diff --git a/source/basic.tex b/source/basic.tex index bd155ed606..8b56d12722 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -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 @@ -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 @@ -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 } @@ -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} @@ -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 diff --git a/source/classes.tex b/source/classes.tex index e13097d465..e6f8c216c2 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -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, @@ -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 { };