mac*_*nir 32

其他人已经解决了post和pre增量之间的功能差异.

左值而言,i++无法分配,因为它不引用变量.它指的是计算值.

在分配方面,以下两种方式都没有任何意义:

i++   = 5;
i + 0 = 5;
Run Code Online (Sandbox Code Playgroud)

因为预增量返回对增量变量的引用而不是临时副本,所以++i是左值.

当你增加类似迭代器对象(例如在STL中)的东西时,由于性能原因而倾向于预增量变得特别好,这可能比int更重要.


Joh*_*itb 25

好吧,另一个回答者已经指出了为什么++i左值是将它传递给引用的原因.

int v = 0;
int const & rcv = ++v; // would work if ++v is an rvalue too
int & rv = ++v; // would not work if ++v is an rvalue
Run Code Online (Sandbox Code Playgroud)

第二个规则的原因是允许使用文字初始化引用,当引用是对const的引用时:

void taking_refc(int const& v);
taking_refc(10); // valid, 10 is an rvalue though!
Run Code Online (Sandbox Code Playgroud)

为什么我们要提出一个rvalue.那么,在为这两种情况构建语言规则时会出现这些术语:

  • 我们想要一个定位器值.这将表示包含可以读取的值的位置.
  • 我们想要表示表达式的值.

以上两点取自C99标准,包括这个好的脚注非常有用:

[名称''左值''最初来自赋值表达式E1 = E2,其中左操作数E1需要是(可修改的)左值.它可能更好地被视为表示对象的"定位器值".有时被称为''rvalue'的东西在本国际标准中被描述为''表达的价值''.]

定位器值称为左值,而评估该位置的值称为右值.根据C++标准(谈论左值到右值的转换),这是正确的:

4.1/2:左值表示的对象中包含的值是右值结果.

结论

使用上面的语义,现在很清楚为什么i++没有左值而是右值.因为返回的表达式i不再存在(它递增了!),它只是感兴趣的值.修改返回的值是i++没有意义的,因为我们没有可以再次读取该值的位置.所以标准说它是一个右值,因此它只能绑定到一个引用到const.

但是,相反,返回的表达式++i是位置(左值)i.激发左值到右值的转换,就像int a = ++i;将从中读取值.或者,我们可以为它做一个参考点,然后读出这个值:int &a = ++i;.

另请注意生成rvalues的其他情况.例如,所有临时值都是rvalues,二进制/一元+和减号的结果以及所有不是引用的返回值表达式.所有这些表达式都不是位于命名对象中,而是仅包含值.这些值当然可以由不是常量的对象来备份.

下一个C++版本将包含所谓的rvalue references,即使它们指向nonconst,也可以绑定到rvalue.理由是能够从那些匿名对象中"窃取"资源,并避免副本这样做.假设一个类型有重载前缀++(返回Object&)和后缀++(返回Object),下面会先导致一个副本,而对于第二种情况,它会从rvalue中窃取资源:

Object o1(++a); // lvalue => can't steal. It will deep copy.
Object o2(a++); // rvalue => steal resources (like just swapping pointers)
Run Code Online (Sandbox Code Playgroud)


Nie*_*jou 10

似乎很多人都在解释如何++i使用左值,但不是为什么,为什么 C++标准委员会将此功能放入其中,特别是考虑到C不允许左右这样的事实.从对comp.std.c ++的讨论来看,它似乎可以获取其地址或分配给引用.代码示例摘自Christian Bau的帖子:

   int i;
   extern void f (int* p);
   extern void g (int& p);

   f (&++i);   /* Would be illegal C, but C programmers
                  havent missed this feature */
   g (++i);    /* C++ programmers would like this to be legal */
   g (i++);    /* Not legal C++, and it would be difficult to
                  give this meaningful semantics */

顺便说一句,如果i恰好是内置类型,那么赋值语句如++i = 10调用未定义的行为,因为i在序列点之间修改了两次.


Bil*_*ard 5

我尝试编译时遇到左值错误

i++ = 2;
Run Code Online (Sandbox Code Playgroud)

但是当我把它改成时却没有

++i = 2;
Run Code Online (Sandbox Code Playgroud)

这是因为前缀运算符(++ i)更改了i中的值,然后返回i,因此仍然可以将其分配给.后缀运算符(i ++)更改i中的值,但返回旧的临时副本,赋值运算符无法修改该副本.


回答原始问题:

如果你正在谈论在一个语句中使用增量运算符,就像在for循环中一样,它确实没有区别.Preincrement似乎更有效,因为postincrement必须自行递增并返回临时值,但编译器会优化这种差异.

for(int i=0; i<limit; i++)
...
Run Code Online (Sandbox Code Playgroud)

是相同的

for(int i=0; i<limit; ++i)
...
Run Code Online (Sandbox Code Playgroud)

当您将操作的返回值用作更大语句的一部分时,事情会变得复杂一些.

即便是两个简单的陈述

int i = 0;
int a = i++;
Run Code Online (Sandbox Code Playgroud)

int i = 0;
int a = ++i;
Run Code Online (Sandbox Code Playgroud)

是不同的.您选择将哪个增量运算符用作多运算符语句的一部分取决于预期的行为.简而言之,不,你不能只选择一个.你必须要了解两者.