C++ 基本类型(Primitive Type) 的(const reference type) 参数有何用处?

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年的高级开发工程师)

 

 

 


阅读更多
个人分类: C++ 精意
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭