数组元素和指针值上的新布局

wal*_*nut 5 c++ language-lawyer c++17

考虑以下三个程序:

// 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;
}
Run Code Online (Sandbox Code Playgroud)
// 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;
}
Run Code Online (Sandbox Code Playgroud)
// 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;
}
Run Code Online (Sandbox Code Playgroud)

这些程序在 C++17 中有未定义的行为吗?

我看到的问题是,根据[basic.life]/8指针不会自动引用A我通过placement-new 创建的新对象。std::launder需要明确地实现这一点。因此,成员访问将具有未定义的行为,因为它是在其生命周期之外的对象上完成的。

至少对于程序 3 来说,这对我来说似乎很清楚,但是对于程序 1,根据[intro.object]/2,新创建的对象成为数组的子对象,因此应该通过指针算术来访问它,不是吗?

然后程序 2 也不会有未定义的行为,因为指针算法只需要a指向数组的一个元素,不一定在其生命周期内。

Nat*_*ica 1

我相信[basic.life]/8.3

原始对象的类型不是 const 限定的,并且如果是类类型,则不包含任何类型为 const 限定的非静态数据成员或引用类型,并且

是唯一使您的成员访问代码行为未定义的子句。

在所有三种情况下,a都是两个对象的数组的名称A,因此成员访问是可以的,因为您正在使用A指针来访问A对象。您没有将 char 缓冲区视为 an A,而是将Aas视为A允许的。