2014-06-18
在函数swap的参数中使用reference和pointer
2.4 使用局部静态对象(Local Static Objects)
2.7 定义并使用Template Functions (模板函数)
2.8 函数指针(Pointers to Functions)带来更大的弹性
2.2 调用(invoking)一个函数
2.2.1 Pass by Reference语义
reference扮演着外界与对象之间的一个间接号码牌的角色。只要在型别名称和reference名称之间插入&符号,便声明了一个reference:
1 #include <iostream> 2 using namespace std; 3 4 int main() 5 { 6 int ival=1024; //对象,型别为int 7 int *pi=&ival; //pointer(指针),指向一个int对象 8 int &rval=ival; //reference(化身),代表一个int对象 9 10 //这里不是令rval改为代表jval对象,而是将jval赋值给rval所代表的对象(也就是ival)。 11 int jval=4096; 12 rval=jval; 13 14 ival =2048; 15 pi; 16 //这里不是令pi指向rval对象,而是将ival(此为rval所代表之对象)的地址赋给pi 17 pi=&rval; 18 19 return 0; 20 }
重点是:面对reference的所有操作都像面对“reference所代表的对象”所进行的操作一样。
在函数swap的参数中使用reference和pointer
当我们以reference作为函数参数时,情况是一样的,如下代码所示:
1 #include <iostream> 2 void swap(int &, int &); 3 4 int main() 5 { 6 int v1=1; 7 int v2=2; 8 swap(v1,v2); 9 10 v1; 11 v2; 12 13 return 0; 14 } 15 16 void swap(int &val1, int &val2) 17 { 18 int temp=val1; 19 val1=val2; 20 val2=temp; 21 }
运行结果如下图所示:
将参数声明为reference的理由有两个:
- 希望直接对所传入的对象进行修改;
- 为了降低复制大型对象的负担。
如果我们愿意,也可以将参数以pointer形式传递。这和以reference传递的效用相同:传递的是对象地址,而不是整个对象的复制品。唯一的差别是他们的用法不同。如下代码所示:
1 #include <iostream> 2 3 void swap(int *,int *); 4 5 int main() 6 { 7 int v1=1; 8 int v2=2; 9 swap(&v1,&v2); 10 11 v1; 12 v2; 13 14 return 0; 15 } 16 17 18 void swap(int *val1, int *val2) 19 { 20 int temp=*val1; 21 *val1=*val2; 22 *val2=temp; 23 }
但如果swap方法改成如下,变量v1,v2不会调换:
1 void swap(int *val1, int *val2) 2 { 3 int *temp=val1; 4 val1=val2; 5 val2=temp; 6 }
因为上述方法只是更改了指针本身的地址,如下图:
pointer参数和reference参数的差异和用法
pointer可能(也可能不)指向一个实际对象。当我门提领pointer时,一定要先确定其值并非为0。至于reference则必定会代表某个对象。
一般来说,除非你希望在函数内更改参数值,否则建议传递内建型别时,不要使用传址的方式。传址机制主要是作为传递class objects之用。
2.4 使用局部静态对象(Local Static Objects)
fibon_seq()函数是这样一个函数,每次调用时,会计算出Fibonacci数列(元数数目由用户指定),并以一个vector存储计算出来的元素值,然后返回。代码如下:
1 vector<int> fibon_seq( int size ) 2 { 3 if ( size <= 0 || size > 1024 ) 4 { 5 cerr << "Warning: fibon_seq(): " 6 << size << " not supported -- resetting to 8\n"; 7 size = 8; 8 } 9 10 vector<int> elems( size ); 11 12 for ( int ix = 0; ix < size; ++ix ) 13 if ( ix == 0 || ix == 1 ) 14 elems[ ix ] = 1; 15 else elems[ ix ] = elems[ix-1] + elems[ix-2]; 16 17 return elems; 18 }
以上代码有一个问题:每次调用时,都要重新计算。
我们希望,保存已经计算出来的元素。上面代码的局部变量肯定不行。如果将vector对象定义于file scope之中,又过于冒险,它会打乱不同函数之间的独立性,使它们难以理解。
本例的另一个解法便是使用局部静态对象:
1 #include <iostream> 2 #include <string> 3 #include<vector> 4 using namespace std; 5 6 //定义函数 7 const vector<int> *fibon_seq( int); 8 9 int main() 10 { 11 fibon_seq( 5 ); 12 fibon_seq( 4 ); //前4个element都已计算,不会重复计算 13 fibon_seq( 6 ); //只计算还没有计算出来的第6个element 14 15 return 0; 16 } 17 18 const vector<int> *fibon_seq( int size ) 19 { 20 const int max_size = 1024; 21 static vector< int > elems; 22 23 if ( size <= 0 || size > max_size ){ 24 cerr << "fibon_seq(): oops: invalid size: " 25 << size << " -- can’t fulfill request.\n"; 26 return 0; 27 } 28 29 // if size is equal to or greater than elems.size(), 30 // no calculations are necessary ... 31 for ( int ix = elems.size(); ix < size; ++ix ){ 32 if ( ix == 0 || ix == 1 ) 33 elems.push_back( 1 ); 34 else elems.push_back( elems[ix-1]+elems[ix-2] ); 35 } 36 37 return &elems; 38 }