gpt4 book ai didi

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

转载 作者:IT老高 更新时间:2023-10-28 23:18:17 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).

可达的定义在[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 is 可用于进行上述转换,因为我已经强调了部分。

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

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

最佳答案

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

我想一些例子会有所帮助。 reinterpret_casts 下面的每个例子都是一个 int* 指向一个由 10 个 ints 组成的数组的第一个元素到一个 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/51552713/

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