可以使用std :: launder将对象指针转换为其封闭的数组指针吗? [英] Can std::launder be used to convert an object pointer to its enclosing array pointer?

查看:144
本文介绍了可以使用std :: launder将对象指针转换为其封闭的数组指针吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

The current draft standard (and presumably C++17) say in [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指向对象的指针来获取其封闭的数组指针.

So a pointer to an object cannot be reinterpret_cast'd to get its enclosing array pointer.

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

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

要求:p表示内存中字节的地址A.在其生存期内且类型类似于T的对象X位于地址A.通过结果可以访问的所有存储字节都可以通过p(请参见下文)访问.

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] :

备注:每当在核心常量表达式中使用其参数的值时,就可以在核心常量表达式中使用此函数的调用.通过一个指向对象Y的指针值可以到达一个存储字节,如果该对象位于Y占用的存储空间内,则该对象可以与Y进行指针互换,如果Y是一个立即封闭数组对象,数组元素.如果T为函数类型或cv void,则程序格式错误.

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进行上述转换.

Now, at first sight, it seems that std::launder is can be used to do the aforementioned conversion, because of the part I've put emphasis.

但是.如果p指向数组的对象,则根据此定义,数组的字节是 reachable (即使p不能指针可互换地转换为array-pointer),就像洗涤的结果.因此,似乎该定义并未说明此问题.

But. If p points to an object of an array, the bytes of the array is reachable according to this definition (even though p is not pointer-interconvertible to array-pointer), just like the result of the launder. So, it seems that the definition doesn't say anything about this issue.

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

So, can std::launder be used to convert an object pointer to its enclosing array pointer?

推荐答案

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

This depends on whether the enclosing array object is a complete object, and if not, whether you can validly access more bytes through a pointer to that enclosing array object (e.g., because it's an array element itself, or pointer-interconvertible with a larger object, or pointer-interconvertible with an object that's an array element). The "reachable" requirement means that you cannot use launder to obtain a pointer that would allow you to access more bytes than the source pointer value allows, on pain of undefined behavior. This ensures that the possibility that some unknown code may call launder does not affect the compiler's escape analysis.

我想一些例子可能会有所帮助. reinterpret_cast下面的每个示例都指向一个int*,该int*指向10个int数组中的第一个元素,该元素位于int(*)[10]中.由于它们不是指针可互换的,因此reinterpret_cast不会更改指针值,并且您会得到一个int(*)[10],其值为指向(无论数组是什么)第一个元素的指针".然后,每个示例都尝试通过在强制转换指针上调用std::launder来获取指向整个数组的指针.

I suppose some examples could help. Each example below reinterpret_casts a int* pointing to the first element of an array of 10 ints into a int(*)[10]. Since they are not pointer-interconvertible, the reinterpret_cast does not change the pointer value, and you get a int(*)[10] with the value of "pointer to the first element of (whatever the array is)". Each example then attempts to obtain a pointer to the entire array by calling std::launder on the cast pointer.

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

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

This is OK; you can access all elements of x through the source pointer, and the result of the launder doesn't allow you to access anything else.

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

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

This is undefined. You can only access elements of x2[0] through the source pointer, but the result (which would be a pointer to x2[0]) would have allowed you to access x2[1], which you can't through the source.

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的指针访问尚未访问的任何字节.

This is OK. Again, you can't access through a pointer to x3.a any byte you can't access already.

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 .

This is (intended to be) undefined. You would have been able to reach x4[1] from the result because x4[0].a is pointer-interconvertible with x4[0], so a pointer to the former can be reinterpret_cast to yield a pointer to the latter, which then can be used for pointer arithmetic. See https://wg21.link/LWG2859.

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

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

And this is again undefined, because you would have been able to reach x5.y from the resulting pointer (by reinterpret_cast to a Y*) but the source pointer can't be used to access it.

这篇关于可以使用std :: launder将对象指针转换为其封闭的数组指针吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆