------- 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