Search code examples
c++language-lawyerundefined-behaviorobject-lifetimeplacement-new

Is it undefined behavior to initialize data before placement new?


struct A { //POD class
    char data[10];
    void print() {std::cout << data;}
};
int main() {
    char buffer[11] = "HELLO"; //sets values in buffer
    A* a = new(buffer)A;
    a->print(); // read from memory buffer
    a->~A();
}

From the class' perspective, this is a read from uninitialized memory, but from the memory perspective, the memory was actually initialized. Is this undefined behavior, or merely dangerous?

[Note: For those curious about new(buffer)A and a->~A(), This is called "placement new" and is used to construct objects in a specific buffer in memory. This is was vector does under the covers to construct classes in its internal buffer]


Solution

  • Even though the class member and the array are guaranteed to have the same address in this particular case (based on [basic.compound]/4.3 plus the fact that the requirements on new-expressions don't really allow the compiler to do anything else than put that object right at the beginning of your buffer), I'm pretty sure this is undefined behavior.

    I believe the relevant bit of the standard would be basic.memobj §1:

    When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced ([expr.ass]).

    I'm not aware of any additional wording anywhere in the standard that would in any case give guarantees concerning the initial value of an object based on what was inside the storage it was created in before its lifetime began. Your object is default-initialized and of class type, therefore, the default constructor will be called. There is no mem-initializer for the member in your constructor nor is there a default initializer in the class, therefore, the member will be default-initialized [class.base.init/9.3]. Since the elements of the array are of fundamental type, no initialization will be performed for them. That means that basic.indet §2 applies to any use of the contents of the array (which would happen inside the operator <<)

    If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases […]

    Since your case does not match any of the cases listed as exceptions, your program should have undefined behavior…