iOS中有关C++左值右值的一些理解

OC初级赋值错误

还记得我们在修改一个view的size的时候经常是这么写的:

CGRect frame = self.view.frame;
frame.size.width = 100;
self.view.frame = frame;

为什么不直接赋值呢?像这样呢

self.view.frame.size.width = 100;

可知会报以下错误

Expression is not assignable

在gcc下会抛出以下错误:

 error: lvalue required as left operand of assignment

有没有仔细想过为什么?lvalue是什么东东

左值右值

C/C++编程中不是经常出现术语lvalue(左值)和rvalue(右值),但是一旦出现,它们的语意就不是特别清晰,最经常看到它们的地方是在编译错误和警告信息中。比如,用gcc编译下面的程序:

int userCount() { return 2; }

int main()
{
    userCount() = 2;
    return 0;
}

你会得到

test.c: In function 'main':
test.c:8:5: error: lvalue required as left operand of assignment

是的,这段代码不是合法的并且不是你想写的,但是那个错误信息提到了lvalue,用gcc编译下面的代码:

int& foo()
{
    return 2;
}

现在那个错误为:

testcpp.cpp: Infunction 'int& foo()':
testcpp.cpp:5:12: error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'

再次,那个错误信息提到了难以理解的rvalue。那么在C/C++中lvalue和rvalue意味着什么?

简单定义

lvalue(locator value)代表一个在内存中占有确定位置的对象(换句话说就是有一个地址)。可以被赋值修改等。
rvalue通过排他性来定义,每个表达式不是lvalue就是rvalue。因此从上面的lvalue的定义,rvalue是在不在内存中占有确定位置的表达式。
譬如:

int var;
var = 4;

赋值运算符要求一个lvalue作为它的左操作数,当然var是一个左值,因为它是一个占确定内存空间的对象。另一方面,下面的代码是无效的:

4 = var;        //ERROR!
(var + 10) = 4; //ERROR!

常量4和表达式var+10都不是lvalue(它们是rvalue)。它们不是lvalue,因为都是表达式的临时结果,没有确定的内存空间(换句话说,它们只是计算的周期驻留在临时的寄存器中)。因此给它们赋值没有语意-这里没有地方给它们赋值。
因此现在应该清楚了第一个代码片段的错误信息。userCount返回一个临时的rvalue。尝试给它赋值,userCount()=2,是一个错误;编译器期待在赋值运算符的左部分看到一个lvalue。
不是所有的对函数调用结果赋值都是无效的。比如,C++的引用(reference)让这成为可能:

int globalvar = 20;

int& foo()
{
    return globalvar;
}

int main()
{
    foo() = 10;
    return 0;
}

这里foo返回一个引用,这是一个左值,所以它可以被赋值,当然我们也可以将函数返回值改为指针是同样的效果。实际上,C++从函数中返回左值的能力对于实现一些重载运算符时很重要的。一个普遍的例子是在类中为实现某种查找访问而重载中括号运算符 []。std::map可以这样做。

std::map<int, float> mymap;
mymap[10]=5.6;

给 mymap[10] 赋值是合法的因为非const的重载运算符 std::map::operator[] 返回一个可以被赋值的引用。
以上是我对C/C++左值右值一方面的粗浅理解,更多的其它新增释义和特性可以参考:Understanding lvalues and rvalues in C and C++
通过以上理解我们来回头看下那个错误,首先要搞清一点,OC的点语法只是一种语法糖,本质还是转换成runtime对应的c/c++函数调用,当然对于一些结构体等点调用除外。
self.view.frame是OC语法,这句话会被转换成:

[[self view] frame]

而frame属性是一个CGRect结构,所以frame.size.width是C语言的语法,就是访问CGRect结构中的size字段,同样,width是CGSize结构的一个字段。所以,你这句话实际上等于:

[[self view] frame].size.width = 100f;

也就是相当于C/C++下的:

getframe().size.width = 100f;

而在C语言里,函数的返回值CGRect是一个R-Value,是不能直接给它赋值的,因此,会报错误。
所以,解决办法就是,用一个临时变量保存这个函数的返回值,修改这个临时变量,然后再赋给frame:

CGRect frame = self.view.frame;
frame.size.width = 100;
self.view.frame = frame;

对比总结

@property (nonatomic) CGRect cframe;
@property (nonatomic, strong) PXobj *pxobj;
@property (nonatomic, strong) NSMutableArray *testArr;

分别CGRect、NSObject、数组等三个类型,我们分别赋值:

self.cframe.size.width = 100;//报错
self.pxobj.name = @"aaa";//正常编译
self.testArr[0] = @"3";//正常编译

对于第一个报错,就不在说了以上已着重解释,对于第二种其实在开始的左值右值介绍里面类似引用/指针返回值类型,self.pxobj对应调用的get方法返回的是PXobj对象指针,指针和引用都是可以隐性修改对应的值的,所以是lvalue,当然可以赋值,同理self.testArr[0],经过重载运算符[]返回的也是一个指针引用,也是可以修改对应的值,所以是不会报错的。

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

推荐阅读更多精彩内容