目前的标准草案(想必是C++17)是在[basic.化合物/4]中说的
注意:数组对象及其第一个元素不是指针-可互换的,即使它们有相同的地址。- end注意事项
因此,指向对象的指针不能是reinterpret_castd来获得其包围数组指针。
现在,有std::launder,[ptr.launder1]
template<class T> [[nodiscard]] constexpr T* launder(T* p) noexcept; 要求:p表示内存中一个字节的地址A。一个对象X在其生命周期内,其类型类似于T位于地址A。通过结果可以到达的所有字节存储字节都可以通过p访问(见下文)。
可达性的定义在[ptr.launder3]中
备注:每当核心常量表达式中可以使用其参数的值时,就可以在核心常量表达式中使用该函数的调用。存储字节可以通过指针值到达,指针值指向对象Y (如果它位于Y所占用的存储器内)、指针与Y可转换的对象(如果Y是数组元素,则指针可立即封装数组对象)。如果T是函数类型或cv,则程序格式不正确.
现在,乍一看,由于我强调的部分,std::launder似乎可以用于进行上述转换。
但。如果p指向数组的一个对象,根据这个定义,数组的字节是可以到达的(即使p不是指针-可转换为数组指针),就像清洗的结果一样。所以,这个定义似乎并没有提到这个问题。
那么,std::launder是否可以用于将对象指针转换为其封闭的数组指针?
发布于 2018-07-27 16:05:10
这取决于包围数组对象是否是一个完整的对象,如果不是,是否可以通过指向该封装数组对象的指针有效地访问更多字节(例如,因为它是数组元素本身,或者指针-可与更大的对象相互转换,或者指针-可转换对象是数组元素)。“可达”要求意味着您不能使用launder获得一个指针,该指针将允许您访问比源指针值允许的更多字节,这将导致无法定义的行为的痛苦。这确保了某些未知代码调用launder的可能性不会影响编译器的转义分析。
我想一些例子会有帮助。reinterpret_cast下面的每个示例都是指向10 int数组的第一个元素到int(*)[10]的int*。由于它们不是指针-可互转换的,所以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]的指针)将允许您访问x21,而您不能通过源访问x21。
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])); 这也是未定义的,因为您本来可以从结果指针(通过reinterpret_cast指向Y*)到达Y*,但是不能使用源指针来访问它。
发布于 2018-07-27 08:49:00
备注:任何非精神分裂症的编译器都可能很乐意接受这一点,就像它会接受C风格的转换或重新解释的转换一样,所以只想看看就不是一种选择。
但是IMHO,你的问题的答案是否定的。如果Y是数组元素,则所强调的立即包围数组对象是在注释段落中,而不是在需要的段落中。这意味着,只要“要求”部分得到尊重,其中的备注也适用。由于数组及其元素类型不是相似的类型,因此不能满足需求,不能使用std::launder。
以下是一般的(哲学?)口译。在K&R C时代(70年代),C是用来取代汇编语言的。因此,规则是:编译器必须服从程序员,前提是源代码可以被翻译。因此,没有严格的混叠规则和指针不再是一个具有附加算术规则的地址。这在C99和C++03中发生了很大变化(更不用说C++11 +了)。现在,程序员应该使用C++作为一种高级语言。这意味着指针只是允许访问给定类型的另一个对象的对象,数组及其元素类型是完全不同的类型。内存地址现在只不过是实现细节而已。因此,试图将指向数组的指针转换为指向其第一个元素的指针违背了语言的哲学,可能会在编译器的后期版本中咬死程序员。当然,由于兼容性的原因,现实生活中的编译器仍然接受它,但我们甚至不应该尝试在现代程序中使用它。
https://stackoverflow.com/questions/51552713
复制相似问题