初始化引用 [英] Initializing a reference

查看:114
本文介绍了初始化引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

虽然我以为我理解C ++中的 rvalue lvalue 语义,但我似乎再次成为奇怪的例子,证明我不知道蹲下。



但是有两个非常简单和基本的,我不明白他们如何工作。在我编译它们之前,我认为没有什么是可以的,在我看到(1)工作后,我认为(2)也会工作。然而,(1)工程,(2)不:

 (1)const std :: string& s =asd; 

这里会发生什么?我的猜测是,从asd构造一个临时 const字符串对象,然后 s 绑定到该临时对象。



当我删除 const时,会出现一个无效的引用。 限定符:

 (2)std :: string& s =asd 

我收到一个编译器错误(VS 2013):无法从'const char [4]'to'std :: string&'。这似乎反驳了我的理论,因为根据它(我的猜测),一个临时字符串对象将从asd然后 s 分配给它,这将不会产生任何编译错误。



总结:




  • s 绑定?

  • s 绑定到的对象的生命周期是什么?

  • < (1)
    编译和(2)不是( std :: string

    TL; DR

    h2>



    • 要绑定什么?

    • 绑定的对象?


    向新创建的临时 std :: string ,只要 s 就可以生活。


    是什么导致(1)编译和(2)不?


    您不能对非左值引用非常量。



    相关引号



    引用自8.5.3 [dcl.init.ref]:


    引用类型 cv1 T1 由类型
    cv2 T2 的表达式初始化,如下所示:




    • [.. snip,不相关..]

    • 否则[如果右侧不是左值],引用对非易失性const类型的小值引用(即 cv1
      应为 const
      ,或者引用应为右值引用。

      • [.. snip,不相关..]

      • 否则,临时类型 cv1 T1使用
        从非初始化表达式创建和初始化非参考拷贝初始化(8.5)的规则。引用
        然后绑定到临时。如果T1是与T2相关的参考,cv1
        应该是与cv2相同的cv-qualification为cv-qualification
        。如果T1是与T2相关的引用,并且引用是
        值,则初始化表达式不应是一个左值。




    在所有情况下,除了最后一个(即,从初始化器表达式创建和初始化一个
    临时),引用被称为
    直接绑定


    在您的情况下,您需要转换 const char * std :: string ,它引入了 std :: string 的临时类型。由于这不是一个值,所以引用应该是 const



    对于生命周期,看看12.2 [class.temporary]:


    有两个上下文,其中临时表在与完整表达式的结束不同的点被销毁。 [...]



    第二个上下文是当引用绑定到临时时。 [...]

    $






    $ b b
    $ b

    这意味着临时将只要你的 const 引用。



    请注意,标准中还有更多细节,包括一些角点,所以你可能想要完全阅读这些部分。


    Although I thought I understand the rvalue and lvalue semantics in C++, I seem to stomp over and over again into strange examples that prove to me that I don't know squat.

    However there are two very simple and basic ones that I don't understand how they work. Before I compiled them I thought none would be ok, after I saw that (1) works, I thought that (2) would work too. However, (1) works, (2) doesn't:

    (1) const std::string &s = "asd";
    

    What happens here? My guess is that a temporary const string object is constructed from "asd", and then s is bound to that temporary object. But wouldn't then the temporary object be destroyed right after this line so we would be left with an invalid reference?

    When I drop the const qualifier:

    (2) std::string &s = "asd";
    

    I get a compiler error (VS 2013): cannot convert from 'const char [4]' to 'std::string &'. Which seems to disprove my theory, because, according to it (my guess), a temporary string object would be constructed from "asd" and then s assigned to it, which wouldn't generate any compile error.

    So to sum up:

    • To what is s bound?
    • What is the lifespan of the object that s is bound to?
    • What makes (1) compile and (2) not (is it some conversion operators defined in std::string or is it a C++ semantic)?

    解决方案

    TL;DR

    • To what is s binded?
    • What is the lifespan of the object that s is binded to?

    To a newly created temporary std::string, that will life as long as s.

    What makes (1) compile and (2) not?

    You may not make a non-const reference to non-lvalues.

    Relevant quotes

    Quoting from 8.5.3 [dcl.init.ref]:

    A reference to type "cv1 T1" is initialized by an expression of type "cv2 T2" as follows:

    • [ .. snip, not relevant .. ]
    • Otherwise [if the right hand side is not an lvalue], the reference shall be an lvalue reference to a non-volatile const type (i.e., cv1 shall be const), or the reference shall be an rvalue reference.
      • [ .. snip, not relevant .. ]
      • Otherwise, a temporary of type "cv1 T1" is created and initialized from the initializer expression using the rules for a non-reference copy-initialization (8.5). The reference is then bound to the temporary. If T1 is reference-related to T2, cv1 shall be the same cv-qualification as, or greater cv-qualification than, cv2. If T1 is reference-related to T2 and the reference is an rvalue reference, the initializer expression shall not be an lvalue.

    In all cases except the last (i.e., creating and initializing a temporary from the initializer expression), the reference is said to bind directly to the initializer expression.

    In your case, you need to convert const char* to std::string, which introduces a temporary of type std::string. Since this is not an lvalue, the reference is shall be const. This concludes why (2) doesn't work.

    For the lifetime, have a look at 12.2 [class.temporary]:

    There are two contexts in which temporaries are destroyed at a different point than the end of the full-expression. [...]

    The second context is when a reference is bound to a temporary. The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference [...]

    This means that the temporary will as long as your const reference. This concludes why (1) does work.

    Note that there are many more details in the standard, which include some corner cases, so you might want to read those sections completely.

    这篇关于初始化引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆