gpt4 book ai didi

c++ - 可以使用 std::launder 将对象指针转换为其封闭数组指针吗?

转载 作者:可可西里 更新时间:2023-11-01 16:23:47 26 4
gpt4 key购买 nike

当前标准草案(大概是 C++17)在 [basic.compound/4] 中说:

[ Note: An array object and its first element are not pointer-interconvertible, even though they have the same address. — end note ]

所以指向对象的指针不能是reinterpret_cast 'd 获取它的封闭数组指针。

现在,有 std::launder , [ptr.launder/1] :

template<class T> [[nodiscard]] constexpr T* launder(T* p) noexcept;

Requires: p represents the address A of a byte in memory. An object X that is within its lifetime and whose type is similar to T is located at the address A. All bytes of storage that would be reachable through the result are reachable through p (see below).

reachable 的定义在 [ptr.launder/3] 中:

Remarks: An invocation of this function may be used in a core constant expression whenever the value of its argument may be used in a core constant expression. A byte of storage is reachable through a pointer value that points to an object Y if it is within the storage occupied by Y, an object that is pointer-interconvertible with Y, or the immediately-enclosing array object if Y is an array element. The program is ill-formed if T is a function type or cv void.

现在,乍一看,似乎std::launder由于我强调的部分,它可以用于进行上述转换。

但是。如果p指向数组的对象,根据此定义,数组的字节可达(即使 p 不能指针互转换为数组指针),就像 launder 的结果.所以,这个定义似乎并没有说明这个问题。

那么,可以std::launder用于将对象指针转换为其封闭数组指针?

最佳答案

这取决于封闭数组对象是否是一个完整的对象,如果不是,您是否可以通过指向该封闭数组对象的指针有效地访问更多字节(例如,因为它本身是一个数组元素,或者指针可与一个更大的对象,或者指针可与作为数组元素的对象相互转换)。 “可达”要求意味着您不能使用 launder 来获得一个指针,该指针允许您访问比源指针值允许的更多字节,否则会出现未定义的行为。这确保了一些未知代码可能调用launder的可能性不会影响编译器的逃逸分析。

我想一些例子会有所帮助。下面的每个示例 reinterpret_cast 都是一个指向 10 个 int 数组的第一个元素的 int* 到一个 int(*)[ 10]。由于它们不是指针可相互转换的,reinterpret_cast 不会更改指针值,您会得到一个 int(*)[10],其值为“指向(无论数组是什么)的第一个元素”。然后,每个示例都会尝试通过对转换指针调用 std::launder 来获取指向整个数组的指针。

int x[10];
auto p = std::launder(reinterpret_cast<int(*)[10]>(&x[0]));

这没关系;您可以通过源指针访问 x 的所有元素,而 launder 的结果不允许您访问任何其他内容。

int x2[2][10];
auto p2 = std::launder(reinterpret_cast<int(*)[10]>(&x2[0][0]));

这是未定义的。您只能通过源指针访问 x2[0] 的元素,但结果(将是指向 x2[0] 的指针)将允许您访问x2[1],你不能通过源。

struct X { int a[10]; } x3, x4[2]; // assume no padding
auto p3 = std::launder(reinterpret_cast<int(*)[10]>(&x3.a[0])); // OK

这没关系。同样,您无法通过指向 x3.a 的指针访问您无法访问的任何字节。

auto p4 = std::launder(reinterpret_cast<int(*)[10]>(&x4[0].a[0])); 

这是(打算)未定义的。您本来可以从结果中得到 x4[1],因为 x4[0].a 可以与 x4[0] 进行指针互换>,因此指向前者的指针可以通过 reinterpret_cast 生成指向后者的指针,然后可用于指针运算。参见 https://wg21.link/LWG2859 .

struct Y { int a[10]; double y; } x5;
auto p3 = std::launder(reinterpret_cast<int(*)[10]>(&x5.a[0]));

这又是未定义的,因为您可以从结果指针到达 x5.y(通过 reinterpret_castY*) 但不能使用源指针访问它。

关于c++ - 可以使用 std::launder 将对象指针转换为其封闭数组指针吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52039886/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com