格式错误:
int &z = 12;
正确形式:
int y;
int &r = y;
问题:
为什么第一个代码错误?标题错误的“含义”是什么?
格式错误:
int &z = 12;
正确形式:
int y;
int &r = y;
问题:
为什么第一个代码错误?标题错误的“含义”是什么?
(ostringstream() << "x=" << x).str()
Answers:
C ++ 03 3.10 / 1说:“每个表达式都是左值或右值。” 重要的是要记住,左值与右值是表达式的属性,而不是对象的属性。
左值命名持久存在于单个表达式之外的对象。例如obj
,*ptr
,ptr[index]
,和++x
都是左值。
右值是临时值,它们在它们所居住的完整表达式的结尾(“在分号处”)消失。例如1729
,x + y
,std::string("meow")
,和x++
都是右值。
地址运算符要求其“操作数应为左值”。如果我们可以接受一个表达式的地址,则该表达式为左值,否则为右值。
&obj; // valid
&12; //invalid
int & = 12;
无效,标准说字符串文字是左值,其他文字是右值。
std::string("meow")
构造了一个类型的对象,std::string
并产生了一个右值,该右值指定了该对象,1729
没有副作用,并且产生了值1729作为类型的右值int
。
"Lvalues name objects that persist beyond a single expression."
是100%正确的语句。相反,您的示例(const int &)1
是错误的,因为它不是“命名”对象。
int &z = 12;
在右侧,int
从整数文字创建了一个临时类型的对象12
,但是该临时对象不能绑定到非const引用。因此,错误。与以下内容相同:
int &z = int(12); //still same error
为什么创建一个临时文件?因为引用必须引用内存中的对象,并且要存在对象,所以必须先创建引用。由于该对象未命名,因此它是一个临时对象。它没有名字。从这个解释中,很清楚为什么第二种情况很好。
可以将一个临时对象绑定到const引用,这意味着您可以执行以下操作:
const int &z = 12; //ok
为了完整起见,我想补充一点,C ++ 11引入了rvalue-reference,它可以绑定到临时对象。因此,在C ++ 11中,您可以这样编写:
int && z = 12; //C+11 only
请注意,其中有&&
intead &
。还要注意const
,即使z
绑定到的对象是由integer-literal创建的临时对象,也不再需要该对象12
。
由于C ++ 11引入了rvalue-reference,int&
因此现在称为lvalue-reference。
12
是一个编译时常量,与所引用的数据不同,它不能更改int&
。你可以做的是
const int& z = 12;
void f( vector<int> const & )
,它是惯用的,可以传递不被修改的向量。现在的问题是那f( vector<int>(5) )
将是不正确的,并且用户将不得不提供不同的过载void f( vector<int> v ) { f(v); }
,这是微不足道的。
f( vector<int>(5) )
,编译器创建一个临时文件,然后将引用绑定到该临时文件,并且类似地如果5
直接进行了隐式转换。这允许编译器为功能生成单个签名,并启用功能的单个用户实现。从那以后,为保持一致性,对于常量引用的其余用法定义了类似的行为。
T const & r = *ptr;
,r
该函数中以后对的任何使用都可以替换为*ptr
,并且r
在运行时不需要存在)或者可能必须通过保留其别名的对象地址来实现(考虑将引用存储为对象的成员),该地址是作为自动取消引用的指针实现的。
这些是C ++语言的规则:
12
)组成的表达式是“右值”int &ri = 12;
是非法的构造您必须了解这些是C ++规则。他们就是。
用稍微不同的规则发明另一种语言(例如C ++)很容易。在C ++中,将允许创建带有右值的非常量引用。这里没有矛盾或不可能的事情。
但这会允许一些风险较大的代码,使程序员可能无法获得预期的结果,因此C ++设计人员正确地决定避免这种风险。
引用是“隐藏的指针”(非空),指向可以更改的事物(左值)。您不能将它们定义为常数。它应该是“可变”的东西。
编辑::
我在想
int &x = y;
几乎等于
int* __px = &y;
#define x (*__px)
其中__px
是一个新名称,并且#define x
仅在包含x
引用声明的块内起作用。
const
:)
const