This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: C++ object model and dynamic type
- From: Michael Matz <matz at suse dot de>
- To: Gabriel Dos Reis <gdr at cs dot tamu dot edu>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Thu, 4 Feb 2010 15:21:30 +0100 (CET)
- Subject: Re: C++ object model and dynamic type
- References: <874olyb6ms.fsf@gauss.cs.tamu.edu> <48781a661002030913m691a0161r813089edad32b8f3@mail.gmail.com>
Hi,
On Wed, 3 Feb 2010, William M. (Mike) Miller wrote:
> > For example, would the following be a valid definition of 'f'?
> >
> > Â Â Âvoid f(int* p) {
> > Â Â Â Â new (p) float(1.2);
> > Â Â Â}
> >
> > My sense is that only objects of compatible types may be stored in
> > a variable, however I do not see a clear statement to that effect in the
> > standard text. ÂNote that restricting to objects of compatible types
> > still allows allocators that use static or automatic storage (since they
> > would be using arrays of characters.)
>
> 3.8p7-9 are intended to address concerns such as these. The
> existing wording primarily addresses class objects and particularly
> class objects with destructors (p7, for instance, which most directly
> applies to your example and requires that the old and new objects
> have the same type, only applies after the lifetime of the original
> object has ended, which only occurs for scalar objects when their
> storage is freed), so we probably need to tweak it a bit to make it
> clear that non-class objects are also covered.
Note that just more explicitely including non-class objects alone will not
render the above definition of 'f' invalid (the program as given will be
invalid, for multiple reasons, one of them 3.8p7). In particular:
- p9 talks about const objects,
- p7 talks about possibilities of when it's possible to use a
pointer, reference or name of the original object to refer to the new
object (amongst other things when the new type is the same as the old
type)
- p8 talks about what is required for types with non-trivial dtors.
p9 doesn't apply in our example, p7 does apply and already now seems to
make your example program invalid, but see below. p8 doesn't apply right
now, but could be made to apply by removing the restriction on non-trivial
dtors. Then it applies and also renders the program invalid. Good. Now
rewrite the program like so:
 Âint g() {
   int i = 3;
   int* p = &i;
new (p) float (1.2);
useme((float*)p);
new (p) int (42);
   return i;
 Â}
Note how p8 (even without the dtor restriction) doesn't render this
program invalid (at scope exit the storage in question holds an object of
the declared type). p7 also doesn't render this invalid: while the
storage holds a float we don't refer to it via the original name, we have
no reference, and we use a pointer to a different object, not the original
pointer (assume that useme() only accesses this as float). And when we
use the original name 'i' later the storage indeed fulfills the
requirements of p7 again.
It would be good to clarify if it's intended that such program be valid,
or if also such intermediate reuse of storage (with proper restoring of
declared types) is intended to be invalid.
Ciao,
Michael.