网站首页 文章专栏 关于<<运算符重载的疑问
关于<<运算符重载的疑问
编辑时间:2019-07-25 10:31:15 作者:bomian 4条评论


    出自:purecpp

    地址: www.purecpp.org

    转载请注明出处!


来说两句吧
登录才能发表评论。
最新评论
  • qicosmos
    ZgblKylin 2019-07-25 11:08:12

    授人以渔的话,详见这两个页面

    https://en.cppreference.com/w/cpp/language/value_category

    https://en.cppreference.com/w/cpp/language/reference


    接下来做点简易的解答分析。

    我不是语言律师,也许解答会有纰漏或者错误,但作为对此类问题的常见场景做个笼统的理解是可以的。

    作者用myInt&类型接收参数,这是一个左值引用

    左值引用,只能绑定到有长期生命周期的对象上,简单来说就是明确定义了变量对象,有起码一个大括号的生存时间的东西。

    而后置自增运算符,返回值是`return temp;`这一句丢出去的,一个拷贝构造生成的临时对象,标准里称其为右值


    右值可以理解为临时对象,典型的就是函数返回值,以及比如写个string("hello world!")构造出来的临时对象。

    最简单粗暴的理解方式,就是左值是可以出现在等号左边,被赋值的东西,所以它必然有个变量名作为标识,有一个大括号(或者全局域)作为确定的生命周期。而右值只能出现在等号右边,可以被传递给别人,但因为没有具体的标识和长久的生命周期。


    题外话说完,回归左值引用。

    Lvalue references can be used to alias an **existing object** (optionally with different cv-qualification)

    左值引用是用于绑定到一个确切存在的对象上。而右值对象只在当前表达式可用,在抽象意义上它只是一个中间值,而不是一个确定的对象。


    那么为什么`const myInt&`又可以了呢?让我们看下右值引用的描述:

    Rvalue references can be used to extend the lifetimes of temporary objects (note, lvalue references to const can extend the lifetimes of temporary objects too, but they are not modifiable through them)

    Note that rvalue references and lvalue references to const extend the lifetimes of temporary objects (see Reference initialization for rules and exceptions).

    也就是说,右值引用,和const左值引用,可以扩展对象的生命周期,让它不会短于这个引用本身的存在时间。


    至于为什么这么设计么,就得翻历史上的故纸堆,看当时指定这些标准时,委员会的大佬们是怎么扯皮的了。

    我们作为使用者,可以不求甚解直接用,也可以类似我前面用等号左边和等号右边的方式来做个简单粗暴的理解,这样比死记硬背要好一点。


    但掌握核心思想是错不了的——左值和右值的划分,核心目的就是为了标识对象的生命周期,来确定这个对象何时可用,何时不可用。

    因此,是先有了生命周期的概念,然后将有固定生命周期和无固定生命周期的场景区分开,于是有了左值和右值。

    然后由于C++是值语义的语言,那么在值传递,和扩展的引用语法中,针对这两个场景,就需要做进一步的细分,于是有了左值引用和右值引用。

    因为右值在抽象概念上是不存在的,只是一个中间态,所以理论上是不存在一个确切的目标对其写入的——所以可变引用的左值引用不能绑定到右值,但不可变的左值引用因为不会写入绑定对象,就开了个口子允许绑定到右值上。


    以上是我自己的一点个人理解,希望能帮到楼主。从语言律师的严格角度来看,我这个解答肯定错误很多,但我觉得,对于引用管理的核心出发点——生命周期,我从这个角度出发去认知这些概念,这个思路应该没什么大问题。

  • qicosmos
    bomian 2019-07-25 12:52:54

    @ZgblKylin 多谢 !!! 有点明白了,++I 我们返回的是myInt& 就相当于返回了myInt的本体,而I++中,因为temp是局部变量不能用引用返回,所以返回了temp,不是本体。可能不规范举例 m=++i;n=i++;前者可以理解i就是m,而后者只是将(i++)这个临时变量赋值给了n 。而如果用myInt& 这就要求必须为 existing object 所以现在是临时变量所以出错。按这个思路:

    1、string a=“123456”;string &b=a; 正确

    2、string &b =string("1234556");错误 因为string("1234556")是个临时的 不符合existing object

  • qicosmos
    qicosmos 2019-07-25 20:52:17
    关于右值和右值引用我再补充一下。先说为什么要增加右值这个概念,因为在C++98中存在无谓的拷贝,一不小心就会导致额外的拷贝,于是C++11中引入右值的概念,即非具名变量就是右值,比如字面量,lambda表达式,非引用返回的函数等等都是右值,当然它们也是临时变量,在c++98中无法直接通过&去取它们的地址,但是我们需要得到右值的地址,那么就增加右值引用,通过右值引用来获取右值的地址。获取了右值的地址有什么用呢,可以实现移动语义,只要你的对象支持了移动构造/赋值,那么你传右值引用参数的时候会自动匹配到移动构造/赋值函数中,在这个函数里就可以做浅拷贝等优化了,不会再像以前一样,临时变量还会存在拷贝,现在有了右值引用和移动语义再也不用担心这个问题了,提高了效率。
  • qicosmos
    bomian 2019-07-26 09:18:58

    认真看了https://en.cppreference.com/w/cpp/language/reference,嘿嘿其实是https://zh.cppreference.com/w/cpp/language/reference 中文版的,了解了左值引用和右值引用的概念,那重新看待上面重载的问题,解决方案1)值传递 2)const 引用传递。c++11中引入了右值引用 && 第三种解决方案就是重载右值引用函数

    3)

    - ostream & operator<<(ostream &out, myInt& obj){...}         //++i

    1. - ostream & operator<<(ostream &out, myInt&& obj){...}       //i++
Absolutely

purecpp

一个很酷的modern c++开源社区


这里有创新的idea,这里有最酷的modern c++代码,这里有很棒的modern c++开源项目。purecpp社区邮箱 purecpp@163.com
友情链接