От: | N. I. | ||
Дата: | 16.07.17 09:23 | ||
Оценка: | 4 (2) |
struct X { const int n; }; X *p = new X{3}; const int a = p->n; new (p) X{5}; // p does not point to new object (3.8) // because X::n is const const int b = p->n; // undefined behavior const int c = std::launder(p)->n; // OK
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 pointer that represents the address of the storage location where the object will be or was located may be used but only in limited ways.
Any pointer of type cv1 T* that represents the address of a storage location suitable to hold an object of type T, but does not point to any object of type cv2 T whose lifetime has started and not ended, may be used but only in limited ways.
PM>The working group has reached consensus that the issue is not a defect in the Standard. A Rationale statement describes the working group's reasoning.
PM>The lifetime of an object or reference is a runtime property of the object or reference. An object is said to have non-vacuous initialization if it is of a class or aggregate type and it or one of its subobjects is initialized by a constructor other than a trivial default constructor. The lifetime of an object of type T begins when:
PM>PM> storage with the proper alignment and size for type T is obtained, and
PM> if the object has non-vacuous initialization, its initialization is complete,
PM>
Drafting note: this maintains the status quo that malloc alone is not sufficient to create an object.
Скрытый текст | |
Peter Dimov: All C code in existence is dead, it just doesn't know it yet. Bjarne Stroustrup: Interesting. Any details? :-) Peter Dimov: Well as I already said,
Richard Smith: One of my main goals in writing P0137 was to clarify the existing language rules. We cannot know whether the language rules express our intent without knowledge or agreement of what the language rules even *are*. Prior to P0137, asking N language lawyers about the above example would have given you probably more than 2N different answers, due the the confused and self-contradictory wording around the description of objects and lifetime. It was never my intent to *stop* after P0137; rather, this was intended to be the starting point for refining the object model to the point where it guarantees some reasonable subset of the implementation details that users have been relying on, while not infringing too heavily on optimizability (that users have *also* been relying on). Now we have a suitably precise framework in order to express questions such as the above and reason about their answers, we can think about exactly which cases we want to have defined behavior, and which cases we want to allow implementations to (let their users) choose between bug detection / optimization and supporting low-level memory manipulation. I'm generally of the opinion that we should require users to be explicit when doing the latter, but making exceptions for some grandfathered-in C compatibility cases should be considered. For instance, I strongly believe the above example *should* be made to have defined behavior in C++. But no ISO C++ standard has ever guaranteed it to have defined behavior -- an implementation is, and always was, at liberty to claim that it violates [basic.lval]/8, because the user never started the lifetime of an 'int' object to store p->b. | |