注册 登录
编程论坛 C++教室

[讨论]反思大家之前讨论过的一个问题

百年不亮 发布于 2007-05-19 19:57, 1211 次点击
之前的一个帖子中提到关于自增前缀和后缀的问题,帖子在这里:https://bbs.bc-cn.net/dispbbs.asp?boardid=56&replyid=58792&id=124908&page=20&skin=0&star=1
int main()
{
int x=5;
int *p=&++x;
int *q=&x++; //error C2102: '&' requires l-value
return 0;
}

Cpp1.cpp
C:\Documents and Settings\Administrator\桌面\daima\Cpp1.cpp(6) : error C2102: '&' requires l-value


最后大家争论的焦点就在为什么&++x合法,而&x++会出错,有人提到我们在c++中重载前缀自增时直接将原始对象加一,最后返回原始对象的引用,所以&++x取的是原始对象的地址,是合法的。而在后缀的实现中是通过将原始对象的值赋给一个临时对象,再将原始对象加一,最后返回临时对象的值,&x++就是取一个临时对象的地址,所以是错误的操作。我看后觉得这是有道理的,但是这只是推测,不敢确定c/c++中内置类型也是这样实现的,近来翻看Bjarne Stroustrup 的 <<The C++ Programming Language>>,发现有一段话如下:

6.2.5 Increment and Decrement
The ++ operator is used to express incrementing directly,rather than expressing it indirectly using a combination of an addition and an assignment. By definition, ++lvaue means lvalue+=1, which again means lvalue=lvalue+1 provided lvalue has no side effects. The expression denoting the object to be incremented is evalued once(ovly). Decrementint is similarly expressed by the -- operator. The operators ++ and -- can be used as both prefix and postfix operators.The value of ++x is the new(that is, incremented)value of x. For example, y=++x is equivalent to y=(x+=1). The value of x++, however, is the old value of x. For example, y=x++ is equivalent to y=(t=x,x+=1,t), where t is a variable of the same type as x.

最后两句话就是我关心的:x++的值是x自增之前的旧值。例如y=x++相当于y=(t=x,x+=1,t),其中t是和x相同类型的变量

对比y=++x is equivalent to y=(x+=1) 和 y=x++ is equivalent to y=(t=x,x+=1,t),可以看出前缀和后缀的本质差别,&++x等价于&(x+=1)即(x+=1,&x); &x++等价于&(t=x,x+=1,t)即&t.

有了Bjarne Stroustrup他老人家的话自己终于放心了。
8 回复
#2
kisscjy2007-05-19 21:02
对比y=++x is equivalent to y=(x+=1)y=x++ is equivalent to y=(t=x,x+=1,t),可以看出前缀和后缀的本质差别,&++x等价于&(x+=1)即(x+=1,&x); &x++等价于&(t=x,x+=1,t)即&t.

呵呵,不看不知道,一看吓一跳~~~

#3
aipb20072007-05-20 17:07
受教了,
#4
神vLinux飘飘2007-05-21 01:49
x++的确是个临时变量,因为是下一次才进行增加
而++x则在这次之前就已经修改好原地址的值了

所以&x++会出现:错误: 单目 ‘&’ 运算中的左值无效
#5
yuyunliuhen2007-05-21 16:33

int main()
{
int x=5;
int *p=&++x;
int *q=&x++; //error C2102: '&' requires l-value
return 0;
}

Cpp1.cpp
C:\Documents and Settings\Administrator\桌面\daima\Cpp1.cpp(6) : error C2102: '&' requires l-value


最后大家争论的焦点就在为什么&++x合法,而&x++会出错,有人提到我们在c++中重载前缀自增时直接将原始对象加一,最后返回原始对象的引用,所以&++x取的是原始对象的地址,是合法的。而在后缀的实现中是通过将原始对象的值赋给一个临时对象,再将原始对象加一,最后返回临时对象的值,&x++就是取一个临时对象的地址,所以是错误的操作。我看后觉得这是有道理的,但是这只是推测,不敢确定c/c++中内置类型也是这样实现的,近来翻看Bjarne Stroustrup 的 <<The C++ Programming Language>>,发现有一段话如下:

“但是这只是推测”这个不只是推测吧,这个说服是对的

这里的情况和操作符重载的返回值是一样的;
比如说有这样的一个类:
class Interger{
private:
//.....
pubic:
friend const Interger operator ++(Interger &a); //prefix
friend const Interger operator ++(Interger &a, int); //postfix
//..some other member-funtion
};
在前缀(++a)和后缀(a++)的版本中,两个版本都改变了对象,这个对象不能作为常量类型,在对象改变后,前缀版本返回真值,我们希望返回改变后的对象,这样,前缀版本只需作为一个引用返回*this,而后缀版本返回改变前的值,必须创建一个代表这个值的对立的对象并且返回他,如果想保持原意,后缀版本必须以值的方式返回。
可以写这样的一个表达式,(++a).func(),那么func()的作用在a上,但如这样写的话(a++).func(),func()的作用在operator++的临时变量上,临时变量自动定为常量,这个操作会被编译器阻止。这个和LZ的例子是同一个道理。

#6
neverDie2007-05-21 18:12
&++a;
&a++ // a++返回的临时变量。
#7
百年不亮2007-05-21 19:44

回5楼的:
我不是说了吗,在自定义类型中,就是我们自己的类中,是这样的,这个是可以肯定的,但是,注意我说的是但是c/c++的内置类型是怎样的,我不知道,在没有一个权威确认的情况下,即使这样是解释的通,我们也只能说推测,不是吗?我在看了Bjarne Stroustrup的书之后才可以确认。
我认为讨论技术问题应该严谨,不能因为自己定义的类中重载++是那样实现的就说内置的类型如int类型也是这样。或许你会说我死板。

#8
leilinghua2007-05-22 22:11
系统分配的临时变量释放了就不能再寻址了
#9
独孤风2007-05-25 20:37

受教了D

1