13.7 通过参数的数据共享问题
首先看一个简单的计算函数:
- void CrossMul( double* X, double *Y, double *Z )
- {
- Z[0] = X[1]*Y[2] - X[2]*Y[1];
- Z[1] = X[2]*Y[0] - X[0]*Y[2];
- Z[2] = X[0]*Y[1] - X[1]*Y[0];
- }
这个函数实现数学上的叉乘运算:
乍一看,这个函数几乎是数学公式的翻版,不可能出错。那么看看下列调用:
- CrossMul( X, Y, X )
这个调用完成下列计算:
将CrossMul()的代码按调用展开,得到:
- X[0] = X[1]*Y[2] - X[2]*Y[1];
- X[1] = X[2]*Y[0] - X[0]*Y[2];
- X[2] = X[0]*Y[1] - X[1]*Y[0];
注意,第三行代码运行时,X[0]和X[1]已经被前两行改写,不再是输入的数据。出现这种错误的原因在于输入参数X和输出参数Z实际上是同一个参数,在计算过程中出现数据共享,有的数据被错误改写,破坏了数据的一致性。
避免这种错误有两个途径,一是调用者不要将同一变量用作两个参数,二是在函数内部使用临时变量,避免数据在计算过程中的共享。第一个途径是对调用者施加的限制。不过,由于在编程(www.cppentry.com)中a=a+b之类的语句大量存在,出于习惯,用户很难遵守这种约定。因此,第二个途径才是唯一可行的方案。代码如下:
- void CrossMul( double* X, double *Y, double *Z )
- {
- int i;
- double Zt[3];
- Zt[0] = X[1]*Y[2] - X[2]*Y[1];
- Zt[1] = X[2]*Y[0] - X[0]*Y[2];
- Zt[2] = X[0]*Y[1] - X[1]*Y[0];
- for( i=0; i<3; i++ )
- Z[i] = Zt[i];
- }
结论是:对于一个函数而言,如果输出参数和输入参数均存在指针或引用时,在计算中可能出现数据共享问题。如果确实存在这个问题,需要使用临时变量存储输出结果,在函数退出时才进行输出参数赋值。
【责任编辑:
董书 TEL:(010)68476606】