尽管我以为我了解C ++中的rvalue
和lvalue
语义,但我似乎一遍又一遍地陷入奇怪的例子中,这些例子向我证明了我不懂蹲坐。
但是,有两个非常简单和基本的功能,我不知道它们是如何工作的。在我编译它们之前,我认为没有什么可以解决的,在我看到它们可行之后(1)
,我认为也(2)
可以。但是,不能(1)
,但是(2)
:
(1) const std::string &s = "asd";
这里会发生什么?我的猜测是,临时const string
对象是从构造的"asd"
,然后s
绑定到该临时对象。但是,那行之后是否会立即销毁临时对象,所以我们将获得无效的引用?
当我取消const
预选赛时:
(2) std::string &s = "asd";
我得到一个编译错误(VS 2013): cannot convert from 'const char [4]' to 'std::string &'
。这似乎反驳了我的理论,因为根据我的猜测(我的猜测),一个临时string
对象将从该对象构造"asd"
然后s
分配给它,而不会产生任何编译错误。
所以总结一下:
s
绑定到什么?s
绑定对象的寿命是多少?(1)
编译而(2)
不是编译(是在其中定义了一些转换运算符std::string
还是C ++语义)?
- 绑定到什么?
- 绑定到s的对象的寿命是多少?
对于一个新近建立的临时住宅std::string
,使用寿命最长s
。
是什么使(1)编译而(2)没有编译?
您不能对非左值进行非常量引用。
从8.5.3 [dcl.init.ref]引用:
类型“
cv1 T1
”的引用由类型“ ”的表达式初始化,cv2 T2
如下所示:
- [..snip,无关。.]
- 否则[如果右侧不是左值],参考应是一个左值参照非易失性const的类型(即,
cv1
应const
),或参考应一个rvalue参考。
- [.. snip,不相关..]
- 否则,将
cv1
使用非引用复制初始化(8.5)的规则从初始化程序表达式创建和初始化类型为“ T1”的临时文件。然后将引用绑定到临时目录。如果T1与T2相关,则cv1应与cv2具有相同的cv资格或更高的cv资格。如果T1与T2相关,并且该引用是右值引用,则初始化表达式不得为左值。在除最后一种情况以外的所有情况下(即从初始化器表达式创建和初始化临时项),都称该引用直接绑定到初始化器表达式。
在您的情况下,您需要转换const char*
为std::string
,从而引入type的临时类型std::string
。由于这不是左值,因此引用应为const
。这说明了为什么(2)不起作用。
一生中,请看12.2 [class.temporary]:
在两种情况下,临时变量在与完整表达式结束时不同的位置被销毁。[...]
第二种情况是引用绑定到临时项时。引用所绑定的临时对象或引用所绑定的子对象的完整对象的临时对象在引用的生存期内一直存在[...]
这意味着该临时文件只要您const
参考即可。这就得出了为什么(1)起作用的结论。
请注意,标准中还有许多详细信息,其中包括一些特殊情况,因此您可能需要完整阅读这些部分。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句