C++ 为什么在这里创建对prvalue的左值引用是合法的?
我的代码如下:C++ 为什么在这里创建对prvalue的左值引用是合法的?,c++,c++11,language-lawyer,C++,C++11,Language Lawyer,我的代码如下: #include <vector> #include <iostream> int main(){ for(int& v : std::vector<int>{1,3,5,10}) { std::cout << v << std::endl; v++; // Does this cause undefined behavior? } return 0;
#include <vector>
#include <iostream>
int main(){
for(int& v : std::vector<int>{1,3,5,10}) {
std::cout << v << std::endl;
v++; // Does this cause undefined behavior?
}
return 0;
}
#包括
#包括
int main(){
for(int&v:std::vector{1,3,5,10}){
std::cout基于范围的for循环不是宏扩展,而是一种真正的语言功能。它确实会将临时对象的生存期延长到整个for体。向量可能是PR值,但其中的int
s是左值
向量为prvalue,无法绑定到int&
向量不能绑定到int&
,无论其值类别:)但是,向量中的int
是左值,可以绑定到int&
是因为for range循环只是宏扩展
范围不是宏扩展,它是一种第一类语言构造。
< P>根据C++ ISO规范,将基于循环的范围定义为等价于
{
auto && __range = range_expression ;
for (auto __begin = begin_expr, __end = end_expr;
__begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
请注意,“等效于”并不意味着“扩展为作为宏”,而是“具有与完全相同的行为”。这种等效不是传统意义上的宏(即,它不是一个#define
),而是作为定义基于范围的for循环的语义的正式方式在ISO规范中给出。基于范围的for循环的实现可以是编译器喜欢的任何形式,只要行为与上面给出的行为完全相同
在此上下文中,range\u expression
是一个prvalue,但它随后被绑定到\uuu range
,这是一个左值。扫描\uu range
得到的迭代器也是左值,因此当迭代器被取消引用以生成范围中的各个值时,这些值将是左值
希望这有帮助!基于范围的for
循环绝对不是宏扩展。它是该语言的一个独立结构。尽管向量本身是prvalue,但其成员函数仍然正常运行。因此其操作符[]
(或取消对其迭代器的引用)返回正常的左值引用等
当然,这样的引用只有在向量本身存在的情况下才有效。它的生命周期持续整个基于范围的for
循环(这是标准中基于范围的for
循环规范强制要求的),所以一切都很好
就价值类别而言,与此相同(这也是):
int&i=std::vector{1,2,3}[0];
当然,与基于范围的for
循环不同,这个i
引用会立即挂起。但原理是一样的
还要考虑这一点:该语言无法知道迭代器的运算符*
或向量的运算符[]
返回的左值引用是指其生存期与向量的生存期绑定的对象。它只返回一个左值引用,因此它是可绑定的
据我所知,向量是prvalue,不能绑定到int&,但这个能正常工作吗
我认为您犯的错误是,您将值类别归因于对象而不是表达式;您认为,因为向量对象是prvalue,所以它的元素也是prvalue,因此int&v
不能绑定到这些prvalue
事实上,值类别是表达式的属性,而不是对象的属性:因此,将范围中的元素推理为具有值类别并确定是否允许变量int&v
绑定到这些对象是没有意义的
因此,虽然创建向量的表达式确实是一个prvalue,但创建的向量只是一个正则对象,其元素只是正则对象,所有这些对于从非常量左值引用类型的变量引用来说都是完全有效的
相反,对基于范围的for循环的直观解释给出了正确的答案:变量依次使用范围的每个元素进行初始化,它就可以正常工作
此外,在编译时会检查值类别。如果由于您给出的原因,代码实际上是非法的,则会出现如下编译错误:
error: non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'
int &v = 10;
^ ~~
运行时可能遇到的未定义行为与值类别无关:您可能希望临时向量的生存期在计算范围表达式后立即结束,因此循环变量是指向向量的悬挂引用,该向量在循环体首次启动exe时已被销毁切割
事实上,临时向量的生命周期在整个循环期间都延长了,因此挂起引用也没有问题。我需要重新表述它,但是的,我的意思是向量的成员是prvalue,但为什么你说它们是左值?为什么你说它们是右值?它们是左值,因为你用来访问它们的e向量返回左值引用。Downvoter:你能详细说明这个问题的错误吗?我认为这是完全合法的,并强调了基于范围的for循环如何工作的细微差别。向量不绑定到int&
。其中的成员是。请注意,\u range
不影响引用寿命prvaluestd::vector{1,3,5,10}
的时间扩展(它的标准名称是什么?),这对于理解其工作原理很重要。而std::vector&&uu range
是一个右值引用,但是右值引用在decltype
表达式之外声明后充当左值引用。这是什么意思“但是右值引用充当左值引用”?这听起来比“\uuu range
是一个名称,因此它是一个左值”更让人困惑。虽然可以使用完整规范来解释基于范围的for循环,但这似乎是不必要的。在这种情况下,我认为最好不要这样做(或者至少不要这样做),因为回答问题时,只需简单地回答er
error: non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'
int &v = 10;
^ ~~