赋值运算符

赋值运算符左侧运算对象必须是可以修改的左值。
赋值运算符满足右结合律。

int ival,jval;
ival = jval = 0; //正确,都被赋值为0

复合赋值运算符

赋值、递增和递减运算符_赋值运算符

任意一种复合运算符都等价于:

a = a op b;

唯一的区别是左侧运算对象的求值次数,使用复合运算符只求值一次,使用普通运算符则求值两次,这两次包含:

  • 一次时作为右边子表达式的一部分求值。
  • 另一次是作为赋值运算符的左侧对象求值。
递增和递减运算符

递增递减运算符有两个版本:

  • 前置版本,将运算对象加1或者减1,然后将改变后的对象作为求值的结果。
  • 后置版本,将运算对象加1或者减1,但是求值结果是运算对象改变之前的值。
  • 前置版本将对象本身作为左值返回。
  • 后置版本将对象原始值的副本作为右值返回。

注意:
除非必须,否则不要使用递增递减的后置版本。
前置版本的递增运算符避免了不必要工作,它把值加1后直接返回改变了的运算对象,与之相比,后置版本则需要将原始值存储下来以便返回这个未修改的值,如果我们不需要修改前的值,那么后置版本操作就是一种浪费。
对于整数和指针而言,编译器可能对这种额外的工作进行一定的优化,但是对于迭代器类型,这种额外的开销消耗巨大,建议使用前置版本。

在一条语句中混用解引用和递增运算符

如果想在一条复合表达式中即将变量的加1或减1又要使用它原来的值,此时就必须采用递增或递减的后置版本。
例如,循环输出一个vector中的内容,直到遇到第一个负值为止:

auto pbeg = v.begin();
while(pbeg != v.end() && &pbeg >=0)
    cout<<*pbeg++<<endl;

预算对象可按任意顺序求值

大多数运算符没有堆顶运算对象的求值顺序,如果一条子表达式改变了某个运算对象的值,另一个子表达式又要使用这个值的话,运算对象的求值顺序就十分关键。因为递增和递减运算符会改变对象的值,所以要地方在复合表达式中错用这两个运算符。

while(beg != s.end() &&!isspace(*beg))
    *beg = toupper(*beg++);     //错误,该赋值语句未定义

赋值运算符左右两端的运算对象都用到了 beg,并且右侧的运算对象还改变了 beg 的值,所以该赋值语句是未定义的,编译器可以按照下面任意一种思路来处理该表达式:

*beg = toupper(*beg);       //如果先求左侧的值
*(beg+1) = toupper(*beg);   //如果先求右侧的值