C++中的边际效应(Side Effect)与顺序点(Sequence Point)问题
转自水木BBS
副作用真是一个很头痛的问题。初学者头痛是因为它令人迷惑,老鸟头痛是因为它会冷不
防叮你一口,只要你稍微粗心一点。当然,老碰到问这样问题的人也让人头痛。
为了理解副作用带来的困难,必须要理解C++中的时序点(Sequence Point)的概念。根据I
SO14882:1998中1.9节第7款的叙述,时序点是前一求值中所有副作用已经结束而下一求值
中任何副作用尚未开始的地方。具体地说,有下面四个地方:
1. 在每一个非子表达式结束的地方。用ISO14882中的术语,就是完全表达式(full-expre
ssion)结束的地方。比如一条表达式语句,函数调用的一个完整参数,if语句里的条件表
达式等等;
2. 在一个函数所有参数求值完以后并且在准备调用该函数之前;
3. 当一个函数返回的时候:就是在返回值已经被复制以后,而在运行该函数的任何外部之
前;
4. 在下列表达式中的第一个表达式之后,假设这里用的都是内置的运算符而没有被重载:
// expr1 && expr2
// expr1 || expr2
// expr1 ? expr2 : expr3
// expr1, expr2
理解了时序点的概念以后,其他的问题就迎刃而解了。C++里说的是,如果在两个时序点之
间有两个或者多个副作用,那么这些副作用的时序是不定的。如果表达式的值依赖于这些
副作用间的顺序,那么表达式的值也就是不定的。
i=i++;显然就属于这种情况,如果i这里是基本类型的话。而在c.erase(i++)就是另外一种
情况,因为在i++之后调用c.erase之前是有一个时序点的。因此就没有二义性问题。
==============NB的分割线================
说实话,偶看不懂原文的意思,里面有好多怪异的词,譬如“副作用”,“非子表达式”,另外还有一些表达感觉有点蹩脚。可能是偶智商实在太低。
找了几篇更”专业“一点的文章,这里的“副作用”应该就是"Side Effect",个人觉得还是翻译成“边际效应”更贴切一些。
一些关于Side effect和Sequence point文章:
http://en.wikipedia.org/wiki/Sequence_point 其实还是wiki上写的明白。
http://learn.akae.cn/media/ch16s03.html 这差不多是wiki的翻译版,也不错。