表达式的副作用解释【引用】

C++语言中的表达式可分为算术表达式,关系表达式和逻辑表达式等多种类型,但从表达式中变量所起的作用角度来看可分为两类:有副作用的表达式和无副作用的表达式.

1 有关表达式的副作用的概念一般说计算一个表达式的值需要引用一些变量,在表达式求值过程中,需要提取这些变量的值,但并不改变这些变量的值,这样的表达式称为无副作用的表达式. 从传统意义上讲,表达式的作用就是计算,它除了产生一个计算结果外,不应该改变参与计算过程的任何变量的值或产生其它的效应.换句话说,传统意义上的表达 式是不应该有副作用的.因此,绝大多数的高级语言中的表达式都是无副作用的表达式.C++语言兼有高级语言和低级语言的特点,是一种典型的全面支持面向对 象特性的语言,为了运行效率的提高,引用了具有副作用的表达式.一个表达式在求值过程中,对使用的变量不但引用,对它们的值还加以改变,这样的表达式称为有副作用的表达式,或者称这个表达式是有副作用的.

2

对表达式的副作用的分析与理解,有如下四个表达式:1、5*X;2、X+Y;3、X++;4、Y-=18*2.其中表达式1和表达式2是无副作用的表达
式,因为在表达式求值过程中,所引用的变量X和Y的值均未发生变化,例如:已知X=5,Y=10,表达式1的值为25,表达式2的值为15,但X的值仍为
5,Y的值仍为10,而表达式3和表达式4是有副作用的表达式,
因为在求表达式值的过程中,所引用的变量X和Y的值均发生了变化.例如:x和Y的值初始状态下分别是5和10
经计算后,表达式3的值为5,X的值变为6,表达式4的值为一26,Y的值变为一26.

对于给出的表达式,怎样才能正确地判断出它是有副作用的表达式还是无副作用的表达式?主
要原因取决于表达式中出现的操作符.C++语言中的操作符可分为两类:无副作用的操作符和有副作用的操作符.如果一个表达式中引用了具有副作用的操作符,
该表达式就是有副作用的表达式.C++语言引入的具有副作用的操作及相应的操作符包括: (1)赋值(=). (2)复合赋值(+=,一:,
*=,/=,%=,《=,》=,!=,&=,一). (3)前增1,前减1(++, 一一).(4)后增1,后减1(++,
一一).这些操作所作用的对象必须是变量,因此这些操作也可称作用于变量的操作.对于作用于变量的操作,除后增1和后减1以,还有这样一个特点:作为操作
结果的表达式的值就是所作用的变量获得的值.例如执行语句序列:int i=5;count<<
(i+=3);count<<i,后两个输出结果均为8.也就是说表达式的值就存放在所作用的变量中.而对于后增1和后减1操作符,运算后尽
管变量的值和表达式的值不同(表达式的值不能通过变量来表示),但是通过计算表达式的值,确使变量的值发生了变化,例如执行语句序列:int
i=5;cout<<i++;count<<i;后两个输出结果分别是5和6,因此从有副作用的表达式的概念出发,后增1和后减
1操作符仍是有副作用的操作符.
.区别一个表达式是否是有副作用的表达式还可以从计算顺序上进行比较.不带副作用的几个表达式的值,不会因计算顺序不同而不同,例如:设X=3,Y=2,
则3*x与表达式X+Y
的值一定是3*2=6与3+2=5;但是带副作用的表达式与其它表达式之间计算的顺序将非常重要,顺序不同结果也不同,例如:X=3,Y=2,则
(++X)+Y与X+Y++依次计算后,表达式的值分别为6与6,而把两个表达式改变计算次序,先计算,X+Y++,后计算(++X)
+Y,则表达式的值分别为5和7.因此在对多个有副作用的表达式进行计算时,一定要注意表达式的计算次序.

3 指针表达式的副作用有的指针表达式也有副作用,
而产生副作用的原因也是因为使用了具有副作用的操作符.在与指针有关的操作中,++
(前增1)、一一(前减1)、+=、-=以及=这5种操作符用于变量并改变它的值,变量所获得的新值也就是指针表达式的值,因而表达式的值就间接地以变量
形式提供.也就是说,这5种操作符的操作结果(即指针表达式的值)视同变量,可继续对之进行只能对变量才能实施的操作(包括上述5种操作以及取地址、后增
1、后减1),因此象++ (++pk),pk+=&k这样的表达式都是合法的(其中pk是指针变量).对于++
(后增1)和一一(后减1)操作,虽然也作用于变量而且改变它的值,但指针表达式的值与变量所获得的新值不相同,因而表达式的值就不可能以变量形式提供,
而只能以数值的这种更直接的形式提供.也就是说,后增1(或后减1)的操作结果视同常量的数值形式的地址值,因此象(pk++)
++,pk一一十=&k这样的表达式都是非法的(pk是指针变量).*
(间接访问)操作结果视同变量,可继续对之进行只能对变量才能实施的操作;而&
(取地址)作用于变量,但不改变变量的值,其操作的结果视同常量的数值形式的地址值,不可对之进行只能对变量才能实施的操作.对于这两种操作符,都是不具
有副作用的操作符.总之,与数值表达式的副作用有关的结论,对于指针表达式同样适用.在指针表达式中具有副作用的操作符与数值表达式中的具有副作用的操作
符相同.

4 表达式副作用的应用
4.1
逗号表达式 由逗号操作符(即,)将各个表达式连接起来就构成了逗号表达式,即表达式1,表达式2,? ?
,表达式n,逗号表达式的求值顺序是:先计算表达式1的值,然后计算表达2的值,依此类推,最后计算表达式n的值,最后计算出的表达式n的值就作为整个逗
号表达式的值.例如:w--,j+=3,k++,P=w+j+k是一个逗号表达式,若初始状态下w=5,j=6,k=7,那么该逗号表达的值为
21(5+9+7).对于逗号表达式中的每个表达式,除最后一个外,必须是具有副作用的表达式才有意义,如上例.而像
X=5,6+18,72*9,Y=10这个逗号表达式中的表达式6+18和72*9是无副作用的表达式,计算时毫无意义.

4.2
表达式语句
在C++中,任何一个表达式都可以作为一个语句来使用,称为表达式语句,方法是在表达式后加上语句结束符(即;).C++表达式之所以可以作为语句使用,
是因为C++拓展了表达式的概念,把赋值等具有副作用的操作也归入表达式的范畴.一切输入、输出操作都通过函数实现;并无专门的输入、输出语句,而函数调
用也是表达式的一种形式.因此,除了流程控制语句外,其它如赋值、输入、输出等都只能通过表达式实现.表达式作为语句使用时,它的值被舍弃不用,其语句功
能通过它的副作用体现,
因而把无副作用的表达式作为语句使用是毫无意义的,如表达式语句K+19;表达式的值(K与19之和)被舍弃不用,它是无意义的语句;只有把具有副作用的
表达式作为语句使用才有意义,像表达式语句x+=5;表达式的值被舍弃不用,但由于+=是有副作用的操作符,经计算后表达式的值实际已保存在变量X中,因
此该表达式语句是有意义的.总之,C++语言中表达式的副作用并不一定是坏东西,理解好它的概念,掌握有副作用的操作符,这样才能处理好它,给自己设计的
程序带来较高的运行效率.

时间: 2024-07-31 14:27:12

表达式的副作用解释【引用】的相关文章

[二] java8 函数式接口详解 函数接口详解 lambda表达式 匿名函数 方法引用使用含义 函数式接口实例 如何定义函数式接口

函数式接口详细定义 package java.lang; import java.lang.annotation.*; /** * An informative annotation type used to indicate that an interface * type declaration is intended to be a <i>functional interface</i> as * defined by the Java Language Specificat

php 常用 正则 表达式 匹配 符号 解释

常用正则表达式全部符号解释 字符 描述 \ 将下一个字符标记为一个特殊字符.或一个原义字符.或一个 向后引用.或一个八进制转义符.例如,'n' 匹配字符 "n".'\n' 匹配一个换行符.序列 '\\' 匹配 "\" 而 "\(" 则匹配 "(". ^ 匹配输入字符串的开始位置.如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置. $ 匹配输入字符串的结束位置.如果设置了

Lambda表达式之方法的引用

以下都是示例 public class Syntax3 { public static void main(String[] args) { //方法引用 //可以快速的将一个lambda表达式的实现指向一个已经实现的方法. //语法: 方法的隶属者 :: 方法名 //注意: //1. 参数数量和类型一定要和接口中定义的方法一致 //2. 返回值的类型也要和接口定义的方法一致 LambdaSingleReturnSingleParameter lambda = a -> change(a); l

正则 表达式(替换)// 引用

replace方法的语法是:stringObj.replace(rgExp, replaceText) 其中stringObj是字符串(string),reExp可以是正则表达式对象(RegExp)也可以是字符串(string),replaceText是替代查找到的字符串..为了帮助大家更好的理解,下面举个简单例子说明一下 Js代码 1. <script language="javascript"> 2. var stringObj="终古人民共和国,终古人民&q

关于ORA-00979 不是 GROUP BY 表达式错误的解释

ORA-00979 不是 GROUP BY 表达式"这个错误,和我前面介绍的另外一个错误ORA-00937一样使很多初学oracle的人爱犯的. 我在介绍使用聚合函数中用group by来分组数据时特别说明了select 列表项中不存在的列可以出现在group by的列表项中,但反过来就不行了,在select列表项中出现的列必须全部出现在group by后面(聚合函数除外) 但一些朋友经常爱把select 列表项的中列忘了写在group by中.于是就出现了以上的错误ORA-00979 不是 G

什么是函数式编程(副作用、纯函数、引用透明)

副作用的概念:一个带有副作用的函数不仅只是简单的返回一个值,还干了一些其他的事情,比如: 修改一个变量 直接修改数据结构 设置一个对象的成员 抛出一个异常或以一个错误终止 打印到终端或读取用户的输入 读取或写入一个文件 在屏幕上绘画 因此我们对于函数式程序的判定边界就在于:函数的副作用. 于是--当函数没有副作用,那么我们就说这个函数符合函数式编程(FP):再给出纯函数这个概念用来定义一个函数没有副作用,我们可以说纯函数构成的程序风格就是函数式的! buyCoffee的例子(p3):函数只不过是

java8之lambda表达式(方法引用)

有些时候,你想要传递给其他代码的操作已经有实现的方法了.示例: button.setOnAction(event -> System.out.println(event); 如果你能够只将println方法传递给setOnAction方法,就更好了!下面是改后的代码: button.setOnAction(System.out::println); 表达式System.out::println是一个方法引用,等同于lambda表达式: x -> System.out.println(x) 正如

C语言中的副作用、序列点、完整表达式

C语言中有个术语叫:副作用 副作用其实是对数据对象或文件的修改.(数据对象的定义是:用于存储值的数据存储区域) 例如语句 states = 50; 从C语言的角度来讲:这个赋值表达式的副作用是将变量的值设置为50:目的是对表达式求值: 但是使用赋值表达式的主要目的(真正目的)就是使用其副作用(将变量的值设置为50): 除此之外,递增.递减运算符也有副作用:我们使用它们其实主要目的是使用其副作用.即递增.递减的副作用: 例如printf()函数,我们使用它的目的是使用其副作用,其副作用是显示信息.

Lambda表达式与方法引用

1 Lambda表达式 1.1 函数式编程思想概述 在数学中,函数就是有输入量.输出量的一套计算方案,也就是"拿数据做数据" 面向对象思想强调"必须通过对象的形式来做事情" 函数式思想则尽量忽略面向对象的复杂语法:"强调做什么,而不是以什么形式去做" 而我们要学的Lambda表达式就是函数式思想的体现 1.2 体验Lambda表达式 需求:启动一个线程,在控制台输出一句话:多线程程序启动了 方式1: 定义一个类MyRunnable实现Runnab