以前已经以各种形式提出过这个问题,但是由于语言规范在这方面似乎是相当动态的(或者至少在对这个问题进行一些SO讨论时是动态的),因此根据最近的发展(如果有的话)重新审视这个问题可能是有意义的。
那么,问题又来了,&
和下标的组合是否是一种有效的方法来获得指向数组
int a[42] = {};
&a[42];
在c++ 98中被认为没有定义。但是现代c++呢?我们已经看到了DR#232,但由于某种原因,它仍处于"起草"状态,绝对不在标准文本中(从c++ 14开始)。这件事还悬而未决,还是已经用别的办法解决了?
有趣的是DR#315似乎公开允许通过空指针p
(!)调用非静态成员函数,其基础是"*p
在p
为空时不会出错,除非将左值转换为右值"。DR#315的分辨率似乎是暂时基于DR#232的未来分辨率,但后者未能实现。从这个角度来看,DR 315真的是NAD吗?
*it
表达式有效的迭代器,在std::vector
的情况下,这可能会在很大程度上将问题委托给原始数组的上述问题,显然为可解引用的std::vector::end()
迭代器打开了大门。这可能使以下代码有效
std::vector<int> v(42);
&v[42];
真的有效吗?一些关于SO的旧答案明确地指出,解引用标准end()
迭代器总是未定义的。但在c++ 11之后的版本中,它似乎没有那么清晰。标准指出,标准库实现"从不假设"end-iterator是可解引用的,这意味着它们不再是无条件不可解引用的。
注:我已经在c++ 14中看到过这种左值不指定对象的讨论,但它似乎特别关注引用初始化的有效性,我不想在这里带来
据我所知,您在&v[42]
(或&a[42]
)表达式中对其进行了解引用,并且未定义。
:
[expr.unary.op]/1
一元*操作符间接执行表达式必须是指向对象的指针类型,或指向函数类型的指针,且结果为左值指向表达式所指向的对象或函数。
我不认为数组最后一个元素之后的非元素是对象
我猜:
除了为类(13.5.5)声明外,下标操作符[]的解释方式如下E1[E2]等于*((E1)+(E2))
a[42]
等于*(a + 42)
[§5.7加性运算符]
当一个整型表达式在指针上加减时,结果具有整型指针操作数的。…
…如果指针操作数和结果都指向同一个数组对象的元素,或一个过去数组对象的最后一个元素,计算不会产生溢出;否则,行为为定义。
所以a + 42
似乎返回一个有效的T*
指针,它将解引用到T
(per [expr.unary.op])
如果表达式的类型是"指向T的指针",则结果的类型是" t "
还有以下注释:
[§3.9.2复合类型]
注意:例如:数组末尾后面的地址(5.7)将被认为指向数组元素类型的一个不相关的对象,该对象可能位于该地址上。
它似乎是有效的。我仍然认为分配给它将是未定义的行为(由于注释,它是一个不相关的对象),但获取地址似乎是定义的。
话虽这么说,&a[41] + 1
是定义的(感谢5.7),并完全避免了这一点,也许只是这样做。