12. 参数传递

当形参是引用类型时,称对应实参被 引用传递 (passed by reference)或者函数被 传引用调用 (called by reference)。

当实参的值被 拷贝 给形参时,形参和实参时两个相互独立的对象。这样的实参被 值传递 (passed by value)或者函数被 传值调用 (called by value)。

12.1. 传值参数

当初始化一个非引用类型的变量时,初始化被拷贝给变量。此时,对变量的改动 不会 影响初始值。

指针形参

指针的行为和其他 非引用 类型一样。当执行指针拷贝操作时,拷贝的是指针的值。拷贝之后, 两个指针是不同的指针 。因为指针 使我们可以间接地访问它所指的对象,所以通过指针 可以修改它所指的对象的值

 1void reset(int* p)
 2{
 3    *p = 0; // 改变了指针p所指对象的值
 4    p = 0; // 只改变了p的局部拷贝,实参未被改变
 5}
 6
 7templtate<class T>
 8void swap(T* x, T* y)
 9{
10    T* tmp = x;
11    x = y;
12    y = tmp;
13}
14//  只交换了拷贝指针的值,实际指针并未改变,因此无法达到交换的目的。

为了改变实参指针的值,可以使用指针的引用或者使用指向指针的指针。

int val = 1;
int* p = &val;

// 调用: reset(p)
void reset(int* &p)
{
    *p = 0; // 改变了指针p所指对象的值
    p = 0; // 改变了指针p的值
}

// 调用: reset(&p)
void reset(int** p)
{
    **p = 0; // 改变了指针*p所指对象的值
    *p = 0; // 改变了指针*p的值
}

12.2. 传引用参数

通过使用引用形参,允许函数改变实参的值。

使用引用避免拷贝:拷贝大的类类型对象或者容器对象比较低效,甚至有的类类型(比如IO类型)根本不支持拷贝操作。当某种类型不支持拷贝操作时,函数只能通过 引用形参访问该类型的对象。例如,需要比较两个string对象,而这样的对象可能会很长,为了避免拷贝且不改变对象的值,可以将形参声明为常量引用(const &)。

使用引用形参返回额外信息:通过给函数传入一个额外的引用形参,让其保存需要的值,而不需要作为函数返回值返回(避免函数返回值太多)。

12.3. 删除指针

如果实参是一个动态申请的指针(new),在函数内 delete 该指针需要慎重。下例基于 Visual Studio 2013。

  • 值传递:删除之后实参指针本身的值不变,指向的值仍然可以访问,但结果是未知的。

     1void delPtr(int* p)
     2{
     3    delete p;
     4}
     5
     6int main()
     7{
     8    int* p = new int(6);
     9    cout << p << ends << *p << endl; // 00746AE0 6
    10    delPtr(p);
    11    cout << p << ends << *p << endl; // 00746AE0 -572662307
    12    return 0;
    13}
    
  • 引用传递:删除之后实参指针本身改变,指向的值不能访问(报错),说明空间得到释放。

     1void delPtr(int* &p)
     2{
     3    delete p;
     4}
     5
     6int main()
     7{
     8    int* p = new int(6);
     9    cout << p << ends << *p << endl; // 006F6AE0 6
    10    delPtr(p);
    11    cout << p << endl; // 00008123
    12    cout << *p << endl; // runtime error
    13    return 0;
    14}
    

12.4. 参考资料

  1. 《C++ Primer 第5版 中文版》 Page 187 – 190。