C++:参数传递"通过引用传递"

Tyl*_*ler 20 c++ parameters reference function

我理解与任何其他变量一样,参数的类型决定了参数与其参数之间的交互.我的问题是,为什么你会引用一个参数vs为什么你不参考?为什么有些函数参数引用而有些参数没有?无法理解这样做的好处,有人可以解释一下吗?

gld*_*ael 49

通过引用传递的能力存在有两个原因:

  1. 修改函数参数的值
  2. 出于性能原因,避免复制对象

修改参数的示例

void get5and6(int *f, int *s)  // using pointers
{
    *f = 5;
    *s = 6;
}
Run Code Online (Sandbox Code Playgroud)

这可以用作:

int f = 0, s = 0;
get5and6(&f,&s);     // f & s will now be 5 & 6
Run Code Online (Sandbox Code Playgroud)

要么

void get5and6(int &f, int &s)  // using references
{
    f = 5;
    s = 6;
}
Run Code Online (Sandbox Code Playgroud)

这可以用作:

int f = 0, s = 0;
get5and6(f,s);     // f & s will now be 5 & 6
Run Code Online (Sandbox Code Playgroud)

当我们通过引用传递时,我们传递变量的地址.通过引用传递类似于传递指针 - 在这两种情况下只传递地址.

例如:

void SaveGame(GameState& gameState)
{
    gameState.update();
    gameState.saveToFile("save.sav");
}

GameState gs;
SaveGame(gs)
Run Code Online (Sandbox Code Playgroud)

要么

void SaveGame(GameState* gameState)
{
    gameState->update();
    gameState->saveToFile("save.sav");
}

GameState gs;
SaveGame(&gs);
Run Code Online (Sandbox Code Playgroud)


由于只传递了地址,因此不需要复制变量的值(对于大型对象来说可能非常大).因此通过引用传递可以提高性能,尤其是

  1. 传递给函数的对象很大(我会在这里使用指针变量,以便调用者知道函数可能会修改变量的值)
  2. 可以多次调用该函数(例如,在循环中)

另外,阅读const参考文献.使用时,无法在函数中修改参数.


Esc*_*alo 23

这篇文章给了我很多帮助.

请忘记现在的指针.并带上一粒盐.

参考对象.当你通过引用传递,传递对象.

传递值时,传递对象的副本 ; 另一个对象.它可能具有相同的状态,但它是一个不同的实例; 一个克隆.

因此,如果您符合以下条件,则可以通过引用传递:

  • 需要修改函数内部对象
  • 不需要(或希望)修改对象,但想避免复制它只是将它传递给一个函数.这将是一个const参考.

如果您符合以下条件,那么传递价值可能是有意义的:

  • 我想从一个完全相同的 双胞胎开始,让原来的双胞胎不受干扰
  • 不关心复制对象的成本(例如,我不会通过int引用传递,除非我想修改它).

在这里,看看这段代码:

#include<iostream>

struct Foo {
  Foo() { }
  void describe() const {
    std::cout<<"Foo at address "<<this<<std::endl;
  }  
};

void byvalue(Foo foo) {
  std::cout<<"called byvalue"<<std::endl;
  foo.describe();
}

void byreference(Foo& foo) {
  std::cout<<"called byreference"<<std::endl;  
  foo.describe();
}

int main() {
  Foo foo;
  std::cout<<"Original Foo"<<std::endl;
  foo.describe();
  byreference(foo);
  byvalue(foo);
}
Run Code Online (Sandbox Code Playgroud)

并像这样编译它: g++ example.cpp

运行: ./a.out

并检查输出(计算机中的实际地址可能不同,但仍然保留点):

Original Foo
Foo at address 0x7fff65f77a0f
called byreference
Foo at address 0x7fff65f77a0f
called byvalue
Foo at address 0x7fff65f779f0
Run Code Online (Sandbox Code Playgroud)

注意called byreference地址如何与地址相同Original Foo(两者都是0x7fff65f77a0f).并注意called byvalue地址是如何不同的(它是0x7fff65f779f0).

把它提升一个档次.修改代码如下:

#include<iostream>
#include<unistd.h> // for sleeping

struct Foo {
  Foo() { }
  Foo(const Foo&) {
    sleep(10); // assume that building from a copy takes TEN seconds!
  }
  void describe() const {
    std::cout<<"Foo at address "<<this<<std::endl;
  }  
};

void byvalue(Foo foo) {
  std::cout<<"called byvalue"<<std::endl;
  foo.describe();
}

void byreference(Foo& foo) {
  std::cout<<"called byreference"<<std::endl;  
  foo.describe();
}

int main() {
  Foo foo;
  std::cout<<"Original Foo"<<std::endl;
  foo.describe();
  byreference(foo);
  byvalue(foo);  
}
Run Code Online (Sandbox Code Playgroud)

以相同的方式编译它,并注意输出(注释不在输出中;为了清楚起见包括在内):

Original Foo
Foo at address 0x7fff64d64a0e
called byreference
Foo at address 0x7fff64d64a0e # this point is reached "immediately"
called byvalue # this point is reached TEN SECONDS later
Foo at address 0x7fff64d64a0f
Run Code Online (Sandbox Code Playgroud)

因此,代码旨在夸大副本的成本:当您通过引用进行调用时,不会产生此成本.当你按价值打电话时,你必须等待十秒钟.

注意:我的代码是使用GCC 4.8.1在OS X 10.7.4中编译的.如果你在Windows中,你可能需要一些不同的东西unitsd.h来使sleep呼叫工作.

也许这有帮助.