Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Placement-new on array elements and pointer values

Consider the following three programs:

// program 1

#include<new>

struct A {
    const int a = 0;
    int b = 0;
};

int main() {
    auto a = new A[2];
    new(a+1) A;
    a[1].b = 1;
}
// program 2

#include<new>

struct A {
    const int a = 0;
    int b = 0;
};

int main() {
    auto a = new A[2];
    new(a) A;
    a[0].b = 1;
}
// program 3

#include<new>

struct A {
    const int a = 0;
    int b = 0;
};

int main() {
    auto a = new A[2];
    new(a) A;
    a->b = 1;
}

Do these programs have undefined behavior in C++17?

The problem I see is that according to [basic.life]/8 pointers will not automatically refer to the new A objects that I am creating via placement-new. std::launder is required explicitly to achieve that. Thus the member access will have undefined behavior as it is done on an object outside its lifetime.

At least for program 3 this seems clear to me, but for program 1, according to [intro.object]/2 the newly created object becomes a subobject of the array and so it should be reached via pointer arithmetic, shouldn't it?

And program 2 would then also not have undefined behavior, because the pointer arithmetic only requires a to point to an element of the array, not necessarily in its lifetime.

like image 873
walnut Avatar asked Nov 07 '22 08:11

walnut


1 Answers

I believe that [basic.life]/8.3

the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type, and

Is the only clause that makes your member access code undefined behavior.

In all three cases a is the name of an array of two A objects so the member access is okay because you are using an A pointer to access an A object. You're not treating a char buffer as an A, you treating an A as and A which is allowed.

like image 191
NathanOliver Avatar answered Nov 15 '22 07:11

NathanOliver