C++ 语言递增和递减运算符

递增运算符 ++ 和递减运算符 -- 为对象的加 1 和减 1 操作提供了一种简洁的书写形式。这两个运算符还可应用于迭代器,很多迭代器本身不支持算术运算,此时递增和递减运算符除了书写简洁外还是必须的。

递增和递减运算符有两种形式:前置版本和后置版本。

  • 前置版本的运算符首先将运算对象加 1 (或减 1),然后将改变后的对象作为求值结果。
  • 后置版本也会将运算对象加 1 (或减 1),但是求值结果是运算对象改变之前那个值的副本。
//============================================================================
// Name        : Yongqiang Cheng
// Author      : Yongqiang Cheng
// Version     : Version 1.0.0
// Copyright   : Copyright (c) 2020 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif#include <stdio.h>//char str[15] = "abcdefg";
//unsigned long long hash_value_v1 = hash_code_v1(str);int main()
{int i = 0, j;j = ++i;  // j = 1, i = 1: 前置版本得到递增之后的值printf("j = %d, i = %d\n", j, i);j = i++;  // j = 1, i = 2: 后置版本得到递增之前的值printf("j = %d, i = %d\n", j, i);return 0;
}
j = 1, i = 1
j = 1, i = 2
请按任意键继续. . .

这两种运算符必须作用于左值运算对象。前置版本将对象本身作为左值返回,后置版本则将对象原始值的副本作为右值返回。

建议:除非必须,否则不用递增递减运算符的后置版本。优先使用前置版本递增递减运算符。

前置版本的递增运算符避免了不必要的工作,它把值加 1 后直接返回改变了的运算对象。与之相比,后置版本需要将原始值存储下来以便于返回这个未修改的内容。如果我们不需要修改前的值,那么后置版本的操作就是一种浪費。

对于整数和指针类型来说,编译器可能对这种额外的工作进行一定的优化;但是对于相对复杂的迭代器类型,这种额外的工作就消耗巨大了。建议养成使用前置版本的习惯,这样不仅不需要担心性能的问题,而且更重要的是写出的代码会更符合編程的初衷。

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

如果我们想在一条复合表达式中既将变量加 1 或减 1 又能使用它原来的值,这时就可以使用递增和递减运算符的后置版本。

可以使用后置的递增运算符来控制循环输出一个 vector 对象内容直至遇到 (但不包括) 第一个负值为止:

 auto pbeg = v.begin();// 输出元素直至遇到第一个负值为止while ((pbeg != v.end) && (*pbeg >= 0)){cout << *pbeg++ << endl;  // 输出当前值并将 pbeg 向前动一个元素}

后置递增运算符的优先级高于解引用运算符,因此 *pbeg++ 等价于 *(pbeg++)pbeg++pbeg 的值加 1,然后返回 pbeg 的初始值的副本作为其求值结果,此时解引用运算符的运算对象是 pbeg 未增加之前的值。最终,这条语句输出 pbeg 开始时指向的那个元素,并将指针向前移动一个位置。

这种用法完全是基于一个事实,即后置递增运算符返回初始的未加 1 的值。如果返回的是加 1 之后的值,解引用该值将产生错误的结果。不但无法输出第一个元素,而且更糟糕的是如果序列中没有负值,程序将可能试图解引用一个根本不存在的元素。

2. 简洁之美

书写

 cout << *iter++ << endl;

要比书写下面的等价语句更简洁、也更少出错

 cout << *iter << endl;++iter;

递增运算会改变运算对象的值,所以要提防在复合表达式中错用这两个运算符。

3. 运算对象可按任意顺序求值

如果一条子表达式改变了某个运算对象的值,另一条子表达式又要使用该值的话,运算对象的求值顺序就很关键了。因为递增运算符和递减运算符会改变运算对象的值,所以要提防在复合表达式中错用这两个运算符。

程序使用 for 循环,将输入的第一个单词改成大写形式:

 for (auto it = s.begin(); it != s.end() && !isspace(*it); ++it){*it = toupper(*it);  // 将当前字符改成大写形式}

在上述程序中,我们把解引用 it 和递增 it 两项任务分开来完成。如果用一个看似等价的 while 循环进行代替将产生未定义的行为。问题在于:赋值运算符左右两端的运算对象都用到了 beg,并且右侧的运算对象还改变了 beg 的值,所以该赋值语句是未定义的。

 // 该循环的行为是未定义的!while (beg != s.end() && !isspace(*beg)){*beg = toupper(*beg++);  // 错误:该赋值语句未定义}

编译器可能按照下面的任意一种思路处理该表达式:

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

也可能采取别的什么方式处理它。

References

(美) Stanley B. Lippman, (美) Josée Lajoie, (美) Barbara E. Moo 著, 王刚, 杨巨峰 译. C++ Primer 中文版[M]. 第 5 版. 电子工业出版社, 2013.
https://www.informit.com/store/c-plus-plus-primer-9780321714114

C++ 语言递增和递减运算符相关推荐

  1. 重载运算与类型转换——基本概念,输入和输出运算符,算术和关系运算符,赋值运算符,下标运算符,递增和递减运算符,成员访问运算符...

    一.基本概念 重载的运算符时具有特殊名字的函数:它们的名字由关键字operator和其后要定义的运算符号共同组成.和其他函数一样,重载的运算符也包含返回类型.参数列表以及函数体. 重载运算符函数的参数 ...

  2. C++primer 第 4 章 表达式 4.1基础 4 . 2 算术运算符 4 .3 逻辑和关系运算符 4 . 4 赋值运算符 4 .5 递增和递减运算符 4.6成员访问运算符

    表达式由一个或多个运算对象(operand)组成,对表达式求值将得到一个结果(result) 字面值和变量是最简单的表达式(expression),其结果就是字面值和变量的值.把一个运算符(opera ...

  3. python中数字逐个递增_Python中递增和递减运算符的行为

    不是运算符.它是两个运算符.运算符是身份运算符,它什么也不做. (澄清:一元运算符只用于数字,但我假设你不会期望一个假设的操作符在字符串上工作.) ++count 解析为 +(+count) 翻译成 ...

  4. java递减_浅谈java的自动递增和递减运算符的使用方法_java运算符_java_课课家

    和C类似,java提供了丰富的快捷运算方式.这些快捷运算可使代码更清爽,更易录入,也更易读者辨读. 两种很不错的快捷运算方式是递增和递减运算符(常称作"自动递增"和"自动 ...

  5. C++ Primer 5th笔记(chap 14 重载运算和类型转换)递增和递减运算符

    并不要求递增和递减运算符一定是类的成员函数,但是因为这个运算符改变的正好是所操作的对象的状态,所以建议将它们设为成员函数. 为了和内置版本保持一致,前置运算符应该返回递增或递减后对象的引用. 为了和内 ...

  6. java递减_关于Java中递增和递减运算符的有趣事实

    关于Java中的递增和递减运算符,有许多有趣的事实.我们将通过示例讨论其中的一些-增量和减量运算符不能与'final'变量一起使用.这是由于与'final'关键字相关联的变量无法更改的事实- 示例pu ...

  7. JavaScript递增和递减运算符

    JavaScript前文回顾: 认识JavaScript到初体验 JavaScript 注释以及输入输出语句 JavaScript变量的使用.语法扩展.命名规范 JavaScript数据类型简介以及简 ...

  8. PHP:递增/递减运算符

    PHP:递增/递减运算符 PHP 支持 C 风格的前/后递增与递减运算符. 注意: 递增/递减运算符不影响布尔值.递减 null 值也没有效果,但是递增 null 的结果是 1. 递增/递减运算符 例 ...

  9. PHP的递增递减运算符有哪些,递增/递减运算符

    PHP 支持 C 风格的前/后递增与递减运算符. Note: 递增/递减运算符不影响布尔值.递减 NULL 值也没有效果,但是递增 NULL 的结果是 1. ### 递增/递减运算符 | 例子 | 名 ...

最新文章

  1. 在k8s中使用gradle构建java web项目镜像Dockerfile
  2. python笔记总结_python学习笔记总结(1)
  3. SURF算法与源码分析、上
  4. 计算机网络第七章:网络安全
  5. Coolite Toolkit学习笔记九:表单布局控件FormLayout与FromPanel
  6. Linux7静默安装Oracle11g教程,亲测实用有效!
  7. linux 同步 多终端,Linux系统如何实现不同终端间的同步
  8. JS事件委托的概念和作用
  9. python处理字符串数组慢_Python字符串处理 - str/bytes
  10. 循环,函数,指针作业
  11. 易飞扬宣布完成100G CWDM4PSM4光模块量产线建设
  12. python开源项目博客_2020年7月最热门的Python开源项目
  13. 2016年前端web开发趋势总结
  14. 93、App Links (应用程序链接)实例
  15. 软交换协议比较和发展趋势 (SIP-T和SIP-I的比较)
  16. 【已解决】最新版本的Chrome浏览器如何设置网页编码
  17. Android TextView 上下滑动 左右滑动设置
  18. 加密解密验签概念理解
  19. Linux 常用命令 一顿操作猛如虎
  20. tortoisegit push 时提示 git did not exit cleanly (exit code 1)

热门文章

  1. 调试、条件处理和防御式编程
  2. 1.3 计算机的性能指标
  3. 一本英文书|让在华外资企业了解中国网络安全等级保护实施条例
  4. 对嵌入式Linux中的根文件系统的理解和解析
  5. 人工智能的“眼睛”:计算机视觉究竟有多厉害?
  6. android 单元测试2016,Android 单元测试
  7. 攻防世界--Misc文件类型
  8. Linux服务器配置与管理(基于Centos7.2)任务目标(四)
  9. 易优cms searchform 搜索标签使用方法
  10. Pipenet v1.7.2.1229 1CD(最新版,管网流体分析软件)