🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.std.c++
Article #2684

Re: an optimization I claim is illegal

#2684
From: Fergus Henderson
Date: Tue, 21 Nov 1995 16:04
112 lines
4636 bytes
martelli@cadlab.it (Alex Martelli) writes:

>In a debate over on comp.compilers, there was some discussion of
>whether it would be legal for a compiler to optimize the following
>snippet of code...:
>
>class P {
>public: virtual void f();
>    // etc
>};
>
>// with a P* p
>    for(i=0;i<1000;i++)
>	p->f();
>
>by hoisting out of the loop the virtual lookup for f()'s address.

Yes, I saw that debate.  I believe that the optimization is legal
according to the current draft standard.  See section 3.8 [basic.life],
"Object Lifetime".  The committee was quite deliberate in its intent to
make sure that this optimizations and other similar optimizations were
legal.

>#include <iostream>
>
>class Base {
>public: virtual void f() {cout<<"Base ";}
>};
>class Derived: public Base {
>    int countdown;
>public: Derived(int n=2):countdown(n) {}
>    virtual void f();
>};
>int main()
>{
>    Base *p=new Derived;
>    for(int i=0;i<4;i++)
>      p->f();
>    cout<<endl;
>    return 0;
>}
>
>and, separately compiled perhaps,
>
>#include <iostream>
>#include <new>
>// above-seen declarations of Base and Derived, then:
>    virtual void Derived::f() {
>	cout<<"Derived ";
>	if(--n==0) {
>	    this->~Derived();
>	    new(this) Base;
>	}
>    }
>
>Isn't this a strictly conformant, well-defined program,

No.  According to 3.8, it has undefined behaviour.  It violates 3.8/6.
The pointer `p' is dereferenced after the lifetime of the object
it points to has ended (since the storage has been reused).

|   3.8  Object Lifetime                                      [basic.life]
| 5 A  program  may  end the lifetime of any object by reusing the storage
|   which the object occupies or by explicitly calling the destructor  for
|   an  object  of  a  class  type  with a non-trivial destructor.
[...]
| 6 After the lifetime of an object has ended and while the storage  which
|   the  object  occupied still exists, any pointer to the original object
|   can be used but only in limited ways.  Such a pointer still points  to
|   valid  storage and using the pointer as a pointer to the storage where
|   the object was located, as if the pointer were of type void*, is well-
|   defined.   However,  using the pointer to refer to the original object
|   is no longer valid.  In particular, such a pointer cannot be  derefer-
|   enced; for a non-POD class type T, a pointer of type T* that points to
|   the  original  object  cannot  be  the  operand   of   a   static_cast
|   (_expr.static.cast_) (except when the conversion is to void* or char*)
|   and cannot be the operand of a dynamic_cast (_expr.dynamic.cast_);  if
|   T  is  a class with a non-trivial destructor, such a pointer cannot be
|   used as the operand of a delete-expression.  [Example:
|           struct B {
|                   virtual void f();
|                   void mutate();
|                   virtual ~B();
|           };
| 
|           struct D1 : B { void f(); };
|           struct D2 : B { void f(); };
|           void B::mutate() {
|                   new (this) D2;  // reuses storage - ends the lifetime of '*th
| is'
|                   f();            // undefined behavior
|                   ... = this;     // ok, 'this' points to valid memory
|           }
| 
|           void g() {
|                   void* p = malloc(sizeof(D1) + sizeof(D2));
|                   B* pb = new (p) D1;
|                   pb->mutate();
|                   &pb;            // ok: pb points to valid memory
|                   void* q = pb;   // ok: pb points to valid memory
|                   pb->f();        // undefined behavior, lifetime of *pb has en
| ded
|           }
|    --end example]

--
Fergus Henderson             	WWW: http://www.cs.mu.oz.au/~fjh
fjh@cs.mu.oz.au              	PGP: finger fjh@128.250.37.3

[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Technical Details
Message-ID: <9532601.3781@mulga.cs.mu.OZ.AU>
Path: arc1-ca.pugleaf.net!engnews1.Eng.Sun.COM!taumet!clamage
References: <martelli.816557310@cadlab>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!engnews1.Eng.Sun.COM!taumet!clamage
From: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Newsgroups: comp.std.c++
Subject: Re: an optimization I claim is illegal
Date: 21 Nov 1995 16:04:40 GMT
Organization: Computer Science, University of Melbourne, Australia
Sender: news@cs.mu.OZ.AU (CS-Usenet)
Approved: clamage@eng.sun.com (comp.std.c++)
Message-ID: <9532601.3781@mulga.cs.mu.OZ.AU>
References: <martelli.816557310@cadlab>
NNTP-Posting-Host: taumet.eng.sun.com
Originator: clamage@taumet