This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug libstdc++/29286] [4.0/4.1/4.2 Regression] placement new does not change the dynamic type as it should



------- Comment #18 from mrs at apple dot com  2006-10-02 19:28 -------
What is your position based upon?  Mine is based upon having been in the room
when we decided what the C rules probably were, what the C++ rules could be and
the up side and down side of each choice and where we decided what our intent
was going to be and lots of word smithing sessions as well.  You can see some
of the depth with which we discussed it in our formulation of the wording in
the standard:

6 Similarly,  before the lifetime of an object has started but after the
  storage which the object will occupy has been allocated or, after  the
  lifetime  of  an  object  has  ended  and before the storage which the
  object occupied is reused or released, any lvalue which refers to  the
  original  object may be used but only in limited ways.  Such an lvalue
  refers to allocated  storage  (_basic.stc.dynamic.deallocation_),  and
  using the properties of the lvalue which do not depend on its value is
  well-defined.  If  an  lvalue-to-rvalue  conversion  (_conv.lval_)  is
  applied  to such an lvalue, the program has undefined behavior; if the
  original object will be or was of a non-POD class  type,  the  program
  has undefined behavior if:

  --the lvalue is used to access a non-static data member or call a non-
    static member function of the object, or

  --the lvalue is implicitly converted (_conv.ptr_) to a reference to  a
    base class type, or

  --the   lvalue   is   used   as   the   operand   of   a   static_cast
    (_expr.static.cast_) (except when the conversion  is  ultimately  to
    char& or unsigned char&), or

  --the   lvalue   is   used   as   the   operand   of   a  dynamic_cast
    (_expr.dynamic.cast_) or as the operand of typeid.

7 If, after the lifetime of an object has ended and before  the  storage
  which  the object occupied is reused or released, a new object is cre-
  ated at the storage location which the  original  object  occupied,  a
  pointer that pointed to the original object, a reference that referred
  to the original object, or the name of the original object will  auto-
  matically  refer  to  the new object and, once the lifetime of the new
  object has started, can be used to manipulate the new object, if:

  --the storage for the new object exactly overlays the storage location
    which the original object occupied, and

  --the  new object is of the same type as the original object (ignoring
    the top-level cv-qualifiers), and

  --the original object was a most derived  object  (_intro.object_)  of
    type  T  and the new object is a most derived object of type T (that
    is, they are not base class subobjects).  [Example:
      struct C {
              int i;
              void f();
              const C& operator=( const C& );
      };
      const C& C::operator=( const C& other)
      {
              if ( this != &other )
              {
                      this->~C();             // lifetime of *this ends
                      new (this) C(other);    // new object of type C created
                      f();                    // well-defined
              }
              return *this;
      }
      C c1;
      C c2;
      c1 = c2;                        // well-defined
      c1.f();                         // well-defined; c1 refers to a new
object of type C
     --end example]

8 If a program ends the lifetime of an object  of  type  T  with  static
  (_basic.stc.static_)  or automatic (_basic.stc.auto_) storage duration
  and if T has a non-trivial destructor,35) the program must ensure that
  an object of the original type occupies  that  same  storage  location
  when  the implicit destructor call takes place; otherwise the behavior
  of the program is undefined.  This is true even if the block is exited
  with an exception.

We explcitly did consider overlaying one type with a completely different type
and did so intend for the standard to allow that.  Further, our intent of
saying that automatics and objects with static duration could be so changed
provided certain conditions were met was meant no only to state that this could
be done, but to state the exact sitations in which it was defined to do so.

> Mike's position is that accessing a variable using its static type is not always safe; I find this bizarre.

Welcome to C++, let me quote the standard:

8 If a program ends the lifetime of an object  of  type  T  with  static
  (_basic.stc.static_)  or automatic (_basic.stc.auto_) storage duration
  and if T has a non-trivial destructor,35) the program must ensure that
  an object of the original type occupies  that  same  storage  location
  when  the implicit destructor call takes place; otherwise the behavior
  of the program is undefined.

If we didn't mean exactly what we wrote, why on earth would we write it?  Hint,
in this, we meant exactlty what was written.  I was there, in every single
meeting where we talked about it.  I know what our intent was, and I know what
the standard says.  At no time does the standard says it is bizarre.  It
prescribe what you, the user _must_ do, if it is to work.  You have to swap the
type back to a valid type, before the system has a chance to notice that the
type is wrong, for it to work, and then, only if there is a non-trivial dtor. 
A trivial dtor doesn't even need to do that, as stated.  You can imagine it
doesn't state


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29286


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]