C++:参数传递"passed by reference"

C++: Argument Passing "passed by reference"

本文关键字:by reference passed C++ 参数传递      更新时间:2023-10-16

我理解与任何其他变量一样,参数的类型决定了参数与其参数之间的交互。 我的问题是,为什么你会引用参数与为什么不引用参数背后的原因是什么? 为什么有些函数参数是引用的,有些不是? 难以理解这样做的好处,有人可以解释一下吗?

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

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

修改参数的示例

void get5and6(int *f, int *s)  // using pointers
{
    *f = 5;
    *s = 6;
}

这可以用作:

int f = 0, s = 0;
get5and6(&f,&s);     // f & s will now be 5 & 6

void get5and6(int &f, int &s)  // using references
{
    f = 5;
    s = 6;
}

这可以用作:

int f = 0, s = 0;
get5and6(f,s);     // f & s will now be 5 & 6

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

例如:

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

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


由于只传递地址,因此不需要复制变量的值(对于大型对象来说可能非常大)。因此,通过引用传递可以提高性能,尤其是在以下情况下:
  1. 传递给函数的对象很大(我会在这里使用指针变体,以便调用者知道函数可能会修改变量的值)
  2. 该函数可以多次调用(例如在循环中)

另外,请继续阅读const参考资料。使用它时,无法在函数中修改参数。

这篇文章对我帮助很大。

请暂时忘记指针。并对此持保留态度。

引用对象。通过引用传递时,传递对象。

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

因此,如果您符合以下条件,则通过引用传递可能是有意义的:

  • 需要修改函数内部的对象
  • 不需要(或想要)修改对象,但希望避免仅仅为了将其传递给函数而复制它。这将是一个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);
}

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

运行它:./a.out

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

Original Foo
Foo at address 0x7fff65f77a0f
called byreference
Foo at address 0x7fff65f77a0f
called byvalue
Foo at address 0x7fff65f779f0

请注意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);  
}

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

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

因此,代码旨在夸大副本的成本:当您通过引用调用时,不会产生此成本。当您按值调用时,您必须等待十秒钟。

注意:我的代码是使用 GCC 4.8.1 在 OS X 10.7.4 中编译的。如果您在窗口中,则可能需要与unitsd.h不同的内容才能使sleep调用正常工作。

也许这会有所帮助。

使用按引用传递的优点:您不必创建数据的副本,只需在内存中传递指向它的指针即可。(巨大的性能胜利,想想如果你有一个你传递的巨大物体)。您可以"返回"多个值 我知道 c/c++ 中的一些函数返回一个数字,其中一个参数是指向纵数据的指针。

使用按引用传递的缺点:您必须小心修改传递的数据,因为它可能会导致您可能想要或可能不希望的副作用。

通过引用同样是通过指针手动传递变量,但通过引用不会让用户处理"容易搞砸"的指针。