C++ 语言的复杂是众所周知的,其中const 和 reference 的语意十分复杂。其中原因,我认为很多来自于C++创始人对于“用户定义类”作为“一等公民”地位的痴迷。
他认为因该把用户定义类当作原始类同等对待。的确,他的目的从语法上来说部分达到了,但是它所衍生的复杂语意,以及编译添加的程序(compiler-instrumented-code),经常使即使经验老到的程序员混淆。
下面我就一个常见的问题作一番研讨:
我们知道,C++ 的const reference 参数对于函数的“非基本类”参数传递很有用,比如下面例子:
// simple class todemonstrate thepoint
class X
{
private:
int_x;
public:
int getX () const { return _x; }
void setX(int x) { _x = x; }
}
// simple X usage
void Foo(const X &x)
{
x.getX(); // OK, no side effect
x.setX(1); // Compile Error: const cannot be changed
}
虽然也可用非const 传递,比如
void Bar(X &x)
{
x.getX(); // OK, noside effect
x.setX(1); // OK,: can be changed
}
但是从程序的“寓意”上来说,Foo 不因该引入副作用(side effect), 即通过x 来改变x代表的原值。
而Bar的“寓意”因该是有副作用的,否则就不应该用X& x 而是应该用 const X &.
对于UDT (用户定义的类)来说,上面例子说明下面4点:
1)const reference 和 reference 在 runtime (运行时)语意是一样的,一般没有性能上的区别(特殊情况下,const 导致临时object,会有影响)。
2)const reference 和 reference 在编译时的语法不一样,前者不许副作用,后者是为了有副作用而设置。
3)const reference 比 reference 的范围狭窄些,是一个很好的“安全”保证,即保证你不会“无意”中修改原值。
4)const reference 的应用相比于直接“传值”(passing by value)来说,因为没有 copy 的语意,一般来说性能要好些。
对于原始类来说,上述区别还有意义吗?比如说
void AddXConst(const int & x) 有没有意义呢?
首先,我们知道 void AddXRef(int& x) 是有意义的,它可以改变原值,比如:
void AddX(int x)
{
x = x +100;// local change, x referenced value not changed
}
void AddXRef(int& x)
{
x = x +100;// x referenced value changed
}
void AddXConst(const int&x)
{
x = x +100;// error: cannot change x
int y = x+ 100; // ok
}
...
int x =100;
AddX(x);
printf("%d",x); //100
AddXRef(x);
printf("%d",x); //200
但是 void AddXConst(const int & x)有用吗?我们知道,在 AddXConst里,x是不能改变的 (编译出错),从寓意上来说,AddXConst应该和AddX完全一样。从性能上来说,因为AddX是传值的,AddXConst是传参考的(passingby reference),所以我的测试结果显示AddX的性能对于简单的运算来说因该是高出AddXConst的5%~30%。
那么,AddXConst这样的用primitiveconst reference type 参数的函数是不是画蛇添足,毫无用处呢?
一般来讲是的!
在罕见的情况下,AddXConst也是有用的:请记住const reference 的 runtime 语意,和 reference 没有区别,所以如果你想改原值,而又不得不接受const时,还是可以考虑的。比如下面“荒唐”的例子,当月亮变红时,我们改变原值:
int changeWhenRedMoon(const int& pi1, const int & pi2)
{
// Rare condition
if(redMoon)
{
const_cast<int&>(pi1)++;
}
// Normal condition
return pi1 + pi2;
}
只是这种应用的机会很少,而且多半有“异味”,是设计有问题的前兆。
2014-8-17 美国西雅图(作者曾是微软总部13年的高级开发工程师)