C++雾中风景10:聊聊左值,纯右值与将亡值

C++11的版本在类型系统上下了很大的功夫,添加了诸如auto,decltype,move等新的关键词来简化代码的编写与降低阅读代码的难度。为了更好的理解这些新的语义,笔者确定通过几篇文章来简单窥探一下C++类型系统的冰山一角,如果加深了对C++类型系统的理解,想必大家也能够更好的应用由C++11带给我们的新"利器"。

1.左值与右值

左值(lvalue)和右值(rvalue)是C++类型系统之中的基础概念,我们不需要了解这些基础概念,同样也能写出代码。但是如果没有弄清左右值的概念,对于许多C++高级特性的探索会一叶障目,所以笔者尝试总结一下自己对于左值与右值的理解。

在C++11之前的版本,基本沿用了C语言之中对于左值与右值的定义,说起来也很简单:“在C++之中的变量只有左值与右值两种:其中凡是可以取地址的变量就是左值,而没有名字的临时变量,字面量就是右值”。 正是因为这两种变量分别位于=的左右两侧,所以被命名为左值与右值。下面,举个栗子:

int x;
int y;

x = 1;
y = 2;
x = y;
y = x;

// 以下代码有误
3 = x;
x + y = 4;

通过上述的代码我们可以快速的理解,显然x,y作为变量可以存在=的左侧,而称之为左值,而3,x + y作为字面量或中间结果,没有办法取得地址,则称之为右值。 这里笔者也给一个简单判定的左右值的方式:
判断能否取值的地址,能取地址的就是左值。

2.将亡值

其实上一节对于左值右值的描述,在我们编写绝大多数代码的场景下并没有什么影响。而在C++11扩展了右值的的概念,将右值分为了纯右值(pure rvalue)将亡值(eXpiring Value)。纯右值的概念等同于我们之前所理解的右值,指的是临时变量或字面量值;而将亡值是C++11新引入的概念,它依托于右值。

左值,纯右值与将亡值

在C++之中,使用左值去初始化对象或为对象赋值时,会调用拷贝构造函数或赋值构造函数。而使用一个右值来初始化或赋值时,会调用移动构造函数或移动赋值运算符来移动资源,从而避免拷贝,提高效率。 而将亡值可以理解为通过移动构造其他变量内存空间的方式获取到的值。在确保其他变量不再被使用、或即将被销毁时,来延长变量值的生命期。而实际上该右值会马上被销毁,所以称之为:将亡值

上述概念阐述的略微抽象,我们来看下面这段代码:
这是我们简单定义的Time类,在类中我们定义了拷贝构造函数和移动构造函数:

class Time {


public:
    int* hour;
    int* minute;
    int* second;

    Time(int h, int m, int s) {
        hour = new int(h);
        minute = new int(m);
        second = new int(s);
    }

    Time(const Time& t) {
        cout << "copy" << endl;
        hour = new int(*t.hour);
        minute = new int(*t.minute);
        second = new int(*t.second);
    }

    Time(Time&& t) noexcept:hour(t.hour),minute(t.minute),second(t.second) {
        t.hour = nullptr;
        t.minute = nullptr;
        t.second = nullptr;
        cout << "move" << endl;
    }

    ~Time() {
        cout << "call ~Time()" << endl;
        delete hour;
        delete minute;
        delete second;
    }

};

接下来我们执行下面的代码:

int main()
{
    Time test(10,25,12);
    Time test2(test);
    return 0;
}

执行结果:

  copy
  call ~Time()
  call ~Time()

由上述代码我们看到test2对象调用了拷贝构造函数来构造了新的对象,这个过程显然是更占用内存的。而接下来,我们尝试利用move函数将test强行转化为将亡值,来避免内存重新分配的过程。但是之后我们也无法再访问test对象的内容了,因为都在移动构造函数之中置为了空指针

int main()
{
    Time test(10,25,12);
    Time test2(move(test));
    return 0;
}

执行结果:

     move
     call ~Time()
     call ~Time()

通过这样的方式来减少不必要的内存操作。但是之后我们也无法再访问test对象的内容了,因为都在移动构造函数之中置为了空指针。将亡值通过移动构造函数”借尸还魂“,通过test2变量延续了自己的生命周期。

3.左值的一些"坑"

虽然笔者给出了左右值分辨的一些基本标准,但是还是有下面一些很让人迷惑的场景:

  • 条件表达式返回左值
true ? i : i;
  • ++
i++ // 左值
++i // 右值
  • []数组取值返回左值
i[10]
  • 指针取值操作符返回左值
*i
  • 字符串字面量返回左值
“hello world”

这是一些表示左值的特殊情况,这里笔者也不展开一一赘述了,希望大家可以简单的进行记忆。当然,笔者从来不去记一些太琐碎的问题,因为太他喵难记了,所以在C++11之中,可以标准库中添加的模板类is_lvalue_reference来判断表达式是否为左值,is_rvalue_reference来判断是否为右值。

  cout << is_lvalue_reference<decltype(i[10])>::value << endl;
  cout << is_rvalue_reference<decltype(i[10])>::value << endl;

返回1则为真,0为假。

4.小结

这只是我们对C++类型系统的第一篇探讨,后续笔者还会继续深入的探讨有关C++11新特性之中与类型系统相关的内容,欢迎大家多多讨论,指教。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容