【问题标题】:Difference between function arguments declared with & and * in C++C++ 中用 & 和 * 声明的函数参数的区别
【发布时间】:2011-08-14 13:47:55
【问题描述】:

我输入了以下示例:

#include <iostream>
double f(double* x, double* y)
{
    std::cout << "val x: " << *x << "\n";
    std::cout << "val y: " << *y << "\n";
    return *x * *y;
}
double f2(double &x, double &y)
{
    std::cout << "val x: " << x << "\n";
    std::cout << "val y: " << y << "\n";
    return x * y;
}
int main()
{
    double a, b;
    a = 2;
    b = 3; 
    std::cout << f(&a, &b) << "\n";
    std::cout << f2(a, b) << "\n";
    return 0;
}   

在函数f 中,我将x 和y 声明为指针,我可以使用*x 获取它们的值。当调用f 时,我需要传递我传递的参数的地址,这就是我传递&amp;a, &amp;b 的原因。 f2是一样的,只是定义不同。

现在我的问题是:它们在内存管理方面真的相同吗?两者都不复制传递的值,而是传递引用? 我想知道f2,因为我无法读出f2x 的地址,所以我知道更多关于f 中x 和y 的信息(我知道地址和值) .

提前致谢!

编辑:好的,谢谢,经过更多研究,我发现了一个非常有用的主题:

Pointer vs. Reference 还有一个指向 google 编码指南 http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Reference_Arguments 的链接,这很像 useful 我觉得(据我现在理解,这是一种主题品味的形式)要更清晰

【问题讨论】:

  • 这不是 C,这是 C++。
  • 啊,我明白了,在 C 语言中我总是必须使用指针,好的,谢谢!目前还不知道!
  • >谷歌风格指南 - 避免它。它在 2008 年(链接的日期)已经过时,今天更糟。
  • @MSalters 避免使用哪一个? 'f' 风格还是 'f2' 风格?
  • @Abhinav:避免使用 Google 风格指南。它已经完全过时了。

标签: c++ function pointers pass-by-reference


【解决方案1】:

这只是语法糖,以避免每次引用参数时都必须使用*。您仍然可以使用&amp;f2 中拥有x 的地址。

【讨论】:

  • 个人认为不止于此。它声明参数不能为空并且不是可选的。有了指针,您永远无法分辨,并且必须始终检查。通过引用,函数签名强制执行程序员的意图并导致更清晰的代码更准确地反映该意图。
  • 另外,指针参数可能需要一个数组。引用参数专门采用一个对象,不需要进一步的文档。
【解决方案2】:

f2 通过引用获取它的参数,这本质上是您传递的参数的别名。指针和引用的区别在于引用不能为 NULL。使用f,您需要将传递给指针的参数的地址(使用& 运算符)传递给指针,当您通过引用传递时,您只需传递参数并创建别名.

当您不打算更改函数内部的参数时,首选通过 const 引用 (const double&amp; ref) 传递,而当您要更改它们时,请使用非 const 引用。

当您需要能够将NULL 传递给您的参数时,通常会使用指针,显然您需要在函数内部检查指针是否不是NULL,然后再使用它。

【讨论】:

  • 为什么有人需要将Null传递给参数?
  • 好吧,如果需要,他们可能需要能够传递 null。显然他们不会一直通过它。
  • 问:“指针和引用的区别在于引用不能为NULL”。最简单明了的答案,什么时候应该和什么时候不使用 * vs & 作为函数参数。别名永远不能为 NULL。
  • f2 和做同样的事情但没有&amp; 所以它就像double f3(double x, double y) 有什么区别?
【解决方案3】:

您应该能够在这两个函数中读取x 地址。

要在f2 中这样做,您当然必须在x 前面加上&amp;,因为在那里,x 是对双精度的引用,并且您想要一个 地址

引用和指针之间值得注意的区别是前者不能为NULL。您必须在提供指针时传递一些东西(有效),如果允许/明确定义传递 NULL,则必须在文档中指定。

另一个区别是可读性问题:使用引用而不是指针(如果可能)可以减少代码中 *-&gt; 的混乱。

【讨论】:

    【解决方案4】:

    另一个未提及的区别是您无法更改引用所指的内容。这与原始问题中显示的函数调用示例没有太大区别。

    int X(10), Y(20);
    int *pX = X;
    int& rY = Y;
    
    *pX = 15; // change value of X
    rY = 25;  // change value of Y
    
    pX = Y;   // pX now points to Y
    

    rY 始终指向Y,不能移动。

    引用不能用于像指针这样的简单数组的索引。

    【讨论】:

      【解决方案5】:

      在我看来,函数的参数总是按值传递。传递int 很容易想象,传递double 只是更大,传递structclass 确实可能非常大。
      但是传递一个指向某个东西的指针,嗯,你只是传递一个地址按值。(指针对于 CPU 来说通常是一个方便的大小,就像int。)
      引用非常相似,当然我认为引用是一个指针,但使用语法糖使它看起来像它所引用的对象已通过值传递。

      您也可以将引用视为const 指针,即:

      int i;
      int j;
      int* p = &i;           // pointer to i
      int* const cp = p;     // cp points to i, but cp cannot be modified
      p = &j;                // OK - p is modified to point to j
      *cp = 0;               // OK - i is overwritten
      cp = &j;               // ERROR - cp cannot be modified
      
      int& ri = i;           // ri refers to i
      ri = 1;                // i is overwritten
      ri = j;                // i is overwritten again
                             // Did you think ri might refer to j?
      

      因此,指针确实是双倍时间:它本身就是一个值,但当您取消引用它时它也可以指向另一个值,例如:*p
      此外,拥有引用参数意味着您不能在函数的生命周期内让它们引用其他任何东西,因为没有办法表达这一点。

      一个引用应该不能用null初始化,但考虑一下:

      void foo(int& i);
      
      int* p = 0;
      foo(*p);
      

      这意味着在使用它们之前应该检查指针,但不能检查引用。 foo() 的实现可能会尝试读取或写入 i,这将导致访问冲突。

      在上面的例子中,指针p应该在用于foo的调用之前进行检查:

      if (p) foo(*p);
      

      【讨论】:

      • 这真的很有帮助,很好的例子。也许您可以在您的 void foo(int&amp; i); 示例中添加评论,以说明使用 NULL 指针调用它到底有什么问题。
      猜你喜欢
      • 1970-01-01
      • 2016-01-03
      • 1970-01-01
      • 2012-11-23
      • 1970-01-01
      • 2015-02-15
      • 2011-09-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多