【问题标题】:Differences between passing by reference and passing by address按引用传递和按地址传递的区别
【发布时间】:2019-02-10 03:19:46
【问题描述】:
int func(int a, int& b){
   if (a < 3){
       return b;
   } else{
       b++;
       return func( a/10, b);
   }
}

我认为这里的 b 是通过指针传递的,这与通过引用传递相同。什么是按地址传递,它与按引用传递有何不同?上面是否有任何变量是通过地址传递的?另外,为什么 func(40, 0) 给我一个错误作为输出?

【问题讨论】:

  • 请仅提出 1 个问题。
  • 指针传递和引用传递是一样的 可以有相似的结果,但相差甚远。
  • 传递指针意味着有可能传递空指针(指向不存在对象的指针)。通过引用传递参数意味着被调用函数 - 以及编译器 - 可以安全地假设传递了一个有效对象 - 调用者无法在不引入未定义行为的情况下传递空引用(例如,通过取消引用空指针)。并且允许编译器在任何时间点假设以前没有未定义的行为。

标签: c++ parameter-passing pass-by-reference


【解决方案1】:

实际上,通过引用传递和通过指针传递并没有太大区别。一些编译器喜欢 MSVC 模型引用完全一样。

然而,在查看细节时,它包含一些令人惊讶的元素:

  • 引用看起来像常规变量,所以不需要 * 或 -> 到处都是
  • 引用不能为 nullptr,允许 static_cast 的代码性能稍高(当你碰巧实现它时,它是未定义的行为)
  • 引用没有固定的内存占用,实际上它是一个指针,但是你不能依赖它
  • 不能重新分配引用,只能更改它指向的东西
  • 引用与 C 不兼容

通常,您可以将引用视为指针的特殊情况(反之亦然)。 就个人而言,我尽量使用引用,并且只在需要时才使用指针。

【讨论】:

  • 引用不能是 nullptr 遗憾的是引用仍然可以是空指针。您只需犯多个错误即可成功。
  • @user4581301:如果它变成了一个 nullptr,那就是未定义的行为。我知道 MSVC 允许这样做,而 Clang 会根据它优化/删除您的代码
  • 为了对 MSVC 公平起见,与其说是允许不如说是可以容忍。但是您看到 MSVC 朝着改进标准一致性的方向发展,所以不要指望这一点。
  • @MSalters 我完全同意
【解决方案2】:

让我试着用简单的方式让你理解。当您在 c++ 程序中声明任何变量时,编译器会在符号表中为该变量创建一个条目,然后在内存中为其提供适当的空间。 在引用变量的情况下,符号表中将有一个新条目,该条目具有相同的引用变量存储,以后不会为它分配空间,它只是一个别名,就像你可能被两个名字引用一样(比如名字,昵称)。 现在让我们以指针变量为例。不管它是一个指针,但它是一个变量,因此它还将具有符号表条目,并且稍后将为它分配空间。

所以从上面的语句你可以很容易地找到地址(指针)和引用变量之间的以下区别 1) 不会为引用变量分配额外的内存,但对于指针变量,将有 4 或 8 个字节取决于您要为其编译和运行代码的系统(32 位或 64 位操作系统)。 2)您以后不能正常地推迟引用变量,因此您不能更改引用,但如果是指针变量,它可以包含不同的指针。

同样适用于引用传递和地址传递。希望它能帮助您更好地理解。

尝试执行下面的代码,你会发现变量和引用变量的地址是一样的

int main()
{
  int i = 10;
  int& j = i;

  printf(" address of i = %u address of j = %u", &i, &j);
  return 0;
}

【讨论】:

  • “不会为引用变量分配额外的内存” 这绝对不能保证。编译器甚至可以以与指针相同的方式实现引用变量。
  • @UnholySheep 大部分情况下不应该有额外的分配,如前所述,符号表中会有一个新条目,一般编译器为引用变量创建一个别名。此外,您可以在函数调用中使用的引用变量的数量也受到限制,我也以某种方式将其与 this 联系起来。
  • @UnholySheep 为了更好地理解添加你可以运行的源代码,你会发现变量和引用变量地址是一样的。
  • 正如many times before 的回答,引用没有自己的地址(因为它们不是对象)。它们仍然(经常)占用空间,您的示例代码并不能证明任何事情
  • 请通过以下链接cs.fsu.edu/~myers/c++/notes/references.html。根据我的理解,如果某些东西占用了内存空间,那么它也应该包含单独的地址,它不应该指向同一个地址。
猜你喜欢
  • 1970-01-01
  • 2014-08-23
  • 2015-05-23
  • 2017-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-22
  • 2011-01-30
相关资源
最近更新 更多