递增运算符(++)和递减运算符(–)为对象的加1和减1操作提供了一种简洁的书写形式。这两个运算符还可以用于迭代器。因为很多迭代器本身并不支持算术运算,所以此时递增运算和递减运算除了书写简洁还是必须的。
递增和递减运算符有两种形式:前置版本和后置版本
int i=0,j;
j=++i;//1
j=i++;//2
- j=1,i=1,前置版本递增之后得到的值
- j=1,i=2,后置版本得到的值
这两种运算符必须要作用于左值运算对象。前置版本将对象本身作为左值返回,后置版本则将对象原始值的副本作为右值返回。
PS:除非必须,建议都不用都增递减的后置版本:原因就在于后置版本相对于前置来说更浪费空间,后置版本需要先将原始值储存下来以便于返回这个未修改的值的内容,如果我们不需要修改前的值,那么后置版本的操作就是一种浪费。
在一条语句中混用解引用和递增运算符
如果我们想在一条复合表达式中既将变量加1或者减1又可以使用它原本的值,这个时候就可以使用递增运算符和递减运算符的后置版本。
举个例子:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v1 = { 1,2,3,4,5,6,7,8,9,0 };
auto pnum = v1.begin();
while (pnum!=v1.end())
{
cout << *pnum++ << " ";
}
return 0;
}
由于刚接触C++,我们对于*pnum++并不了解,我们需要知道的是由于后置递增运算符的优先级要高于解引用运算符,所以这一个其实等效于*(pnum++)。
这种用法完全基于一个事实,即后置递增运算符返回初始值未加1的值,如果返回的 是加1后的值,解引用该值将产生错误的结果。不但无法输出第一个元素,而且更糟糕的是如果这个程序当中没有负值,程序将可能试图解引用一个根本不存在的元素。
运算对象可以按照任意顺序求值
大多数运算符都没有规定运算对象的求值顺序,这在一般情况下不会有什么影响,但是,如果一条子表达式改变了某运算对象的值。另一条表达式又要使用这个值,这样子的话运算顺序就很关键了。因为递增运算符和递减运算符会改变运算对象的值,所以就需要提防在复合表达式中错误使用这两个运算符。
用代码进行描述就是:
#include<iostream>
#include<string>
#include<cctype>
using namespace std;
int main()
{
string s1 = "helloworld";
auto str1 = s1.begin();
while (str1!=s1.end())
{
*str1 = toupper(*str1++);//这一句是重点
}
cout << s1;
return 0;
}
对于上面那句标识重点的句子,我们实际上程序运行他会有两种的运行可能。
- 第一种情况:
*str1 = toupper(*str1);
str1++;
- 第二种情况:
*(str1+1) = toupper(*str1);
在这种情况下,编译器就会相应的无法判断的采用任意一种思路进行处理该表达式,或者报错。
PS:为了避免这种情况,切勿同一行的左右边同时用上递增递减符号。