C++11 将固定数组大小的指针/引用转换为较小的大小是否合法 < P> >根据C++标准,将指针或引用转换为固定数组(例如,代码> T(*)[n] < /代码>或 t(&)[n] < /代码>,以合法地将指针或引用转换为指针或引用相同类型和CV资格的较小固定数组(例如:代码> T(*)[M] < /代码>或 t(&)[M] < /代码>)

C++11 将固定数组大小的指针/引用转换为较小的大小是否合法 < P> >根据C++标准,将指针或引用转换为固定数组(例如,代码> T(*)[n] < /代码>或 t(&)[n] < /代码>,以合法地将指针或引用转换为指针或引用相同类型和CV资格的较小固定数组(例如:代码> T(*)[M] < /代码>或 t(&)[M] < /代码>),c++11,c++,language-lawyer,C++11,C++,Language Lawyer,基本上,这对于T的所有实例化来说都是格式良好的(无论布局类型如何): void消耗(T(&array)[2]); 无效接收(T和数组)[6]) { 消耗(重新解释施法(数组)); } 我看不到以下任何引用是有效的转换: , , ,甚至 然而,似乎所有主要的编译器都接受这一点,即使在使用T=std::string()时进行了优化,也能生成正确的代码(如果这是未定义的行为,这证明不了多少) 我的理解是,根据类型系统,这应该是非法的,因为T[2]的对象从未真正创建过,这意味着T(&)[2]的引

基本上,这对于
T
的所有实例化来说都是格式良好的(无论布局类型如何):

void消耗(T(&array)[2]);
无效接收(T和数组)[6])
{
消耗(重新解释施法(数组));
}
我看不到以下任何引用是有效的转换:

  • ,
  • ,
  • ,甚至
然而,似乎所有主要的编译器都接受这一点,即使在使用
T=std::string
()时进行了优化,也能生成正确的代码(如果这是未定义的行为,这证明不了多少)

我的理解是,根据类型系统,这应该是非法的,因为
T[2]
的对象从未真正创建过,这意味着
T(&)[2]
的引用将无效



我之所以给这个问题加上标签,是因为这是我对答案最感兴趣的版本,但我很想知道这个答案在新版本中是否有所不同。

在任何语言版本中,除了没有,这里没有什么要说的:类型完全不相关。C++20确实允许从
T(*)[N]
转换到
T(*)[]
(对于引用也是如此),但这并不意味着您可以等效地处理两个不同的
N
。最接近此规则的“引用”是[conv.array]/1(“结果是指向数组的第一个元素的指针。”,它在您的示例中不存在
T[2]
)和[defns.undefined]中的注释(“当本文档省略任何显式的行为定义时,可能会出现未定义的行为”)


编译器不会“捕获”您的部分原因是这样的
reinterpret\u cast
s可以有效地在一个对象的真实类型上返回,而另一个
reinterpret\u cast
用于“偷偷”通过一个需要指向不同类型的指针或引用的接口(但不要将其用作该类型!)这意味着给定的代码是合法的,但是
consume
receive
的调用方的明显定义将一起导致未定义的行为。(另一方面,优化器通常会忽略始终未定义的代码,除非它可以消除分支。)

一个迟来的补充答案,它相当于一条评论的质量,但远远超过了允许的内容量:

首先:好问题!值得注意的是,这样一个非常明显的问题很难被验证,甚至在专家中也会产生很多混乱。值得一提的是,我已经经常看到这类代码了

先说说未定义的行为

我认为至少关于指针用法的问题是一个很好的例子,我们必须承认,语言的一个方面的理论上未定义的行为有时会被其他两个方面“击败”:

  • 在某些情况下,是否有其他标准条款可以降低感兴趣方面的UB程度?是否有一些条款在标准中的优先级彼此不明确?(在C++20中仍然存在一些突出的示例,例如,请参见运算符auto()的转换类型id处理…)
  • 是否有(图灵)可证明的论据,任何理论和实际的编译器实现都必须按照您预期的方式运行,因为语言中还有其他约束,必须以这种方式确定它?说即使UB可以奇怪地表示,编译器也可以应用“我可以在这里做我想做的事情,即使是最大的混乱”对于您的情况,可以证明,确保其他指定的(!)语言方面至少在实际上是不可能的
  • 因此,关于第2点,有一个经常被低估的方面:抽象机器的模型有哪些约束(如果可以定义的话),这些约束决定了给定代码的任何理论(编译器)实现的结果

    到目前为止,有很多词,但1)中的任何词是否适用于您的具体案例(指针方式)?

    正如用户在评论中多次提到的,这样做的机会在于:

    两个对象a和b是指针可相互转换的,如果:

    (4.4)存在一个对象c,使得a和c 指针可相互转换,c和b是指针可相互转换的

    这就是传递性的简单规则。我们真的能找到这样一个c(用于数组)吗

    在同一节中,标准进一步说明:

    如果两个对象是指针可相互转换的,则它们具有相同的指针 地址,并且可以从指针获取指向某个地址的指针 通过重新解释向另一方传达。[ 注意:数组对象及其 第一个元素不是指针可相互转换的,即使它们具有 同一个地址。 — 尾注 ]

    在这里,通过指向第一个元素用法的指针摧毁了我们对方法的梦想

    我们还有机会吗?你提到:

    对象指针可以显式转换为 当“指针指向T1”类型的PRV值为 转换为“指向cv T2的指针”类型,如果T1和T2都是标准布局,则结果为静态_cast(静态_cast(v)) 类型([基本类型])和T2的对准要求不适用 比T1更严格,或者如果其中任何一种类型为void “指向T1的指针”类型的prvalue指向“指向T2的指针”类型(其中T1 和T2是对象