270

为函数提供要使用的原始变量时,有什么更好的做法:

unsigned long x = 4;

void func1(unsigned long& val) {
     val = 5;            
}
func1(x);

或者:

void func2(unsigned long* val) {
     *val = 5;
}
func2(&x);

IOW:有什么理由选择一个而不是另一个吗?

4

12 回答 12

296

我的经验法则是:

如果您想对指针进行指针运算(例如,递增指针地址以逐步遍历数组)或者您必须传递一个 NULL 指针,请使用指针。

否则使用参考。

于 2008-09-22T10:40:15.977 回答
74

我真的认为您将从建立以下函数调用编码指南中受益:

  1. 与所有其他地方一样,始终保持const正确。

    • 注意:这意味着,除其他外,只有输出值(参见第 3 项)和按值传递的值(参见第 4 项)可以缺少说明const符。
  2. 如果值 0/NULL 是当前上下文中的有效输入,则仅通过指针传递值。

    • 理由 1:作为调用者,您看到您传入的任何内容都必须处于可用状态。

    • 理由 2:正如所谓的那样,您知道进来的任何东西都处于可用状态。因此,不需要对该值进行 NULL 检查或错误处理。

    • 理由 3:理由 1 和 2 将由编译器强制执行。如果可以的话,总是在编译时捕获错误。

  3. 如果函数参数是输出值,则通过引用传递它。

    • 理由:我们不想破坏第 2 项...
  4. 仅当值是 POD(普通旧数据结构)或足够小(内存方面)或以其他方式足够便宜(时间方面)进行复制时,才选择“按值传递”而不是“按 const 引用传递” 。

    • 理由:避免不必要的副本。
    • 注意:足够小和足够便宜并不是绝对可衡量的。
于 2008-09-22T11:37:17.337 回答
24

这最终是主观的。到目前为止的讨论很有用,但我认为对此没有正确或决定性的答案。很大程度上取决于风格指南和您当时的需求。

虽然指针有一些不同的功能(是否可以为 NULL),但输出参数的最大实际差异是纯语法。例如, Google 的 C++ 样式指南 ( https://google.github.io/styleguide/cppguide.html#Reference_Arguments ) 只要求输出参数的指针,并且只允许 const 引用。推理是可读性之一:具有值语法的东西不应该具有指针语义。我并不是说这一定是对还是错,但我认为这里的重点是风格问题,而不是正确性问题。

于 2008-09-22T13:11:31.400 回答
9

指针

  • 指针是保存内存地址的变量。
  • 指针声明由基类型、* 和变量名组成。
  • 指针可以指向生命周期内任意数量的变量
  • 当前未指向有效内存位置的指针被赋予值 null(为零)

    BaseType* ptrBaseType;
    BaseType objBaseType;
    ptrBaseType = &objBaseType;
    
  • & 是一个一元运算符,它返回其操作数的内存地址。

  • 解引用运算符 (*) 用于访问存储在指针指向的变量中的值。

       int nVar = 7;
       int* ptrVar = &nVar;
       int nVar2 = *ptrVar;
    

参考

  • 引用 (&) 类似于现有变量的别名。

  • 引用 (&) 类似于自动取消引用的常量指针。

  • 它通常用于函数参数列表和函数返回值。

  • 引用必须在创建时进行初始化。

  • 一旦一个引用被初始化为一个对象,就不能改变它来引用另一个对象。

  • 您不能有 NULL 引用。

  • 一个 const 引用可以引用一个 const int。它是使用具有 const 值的临时变量完成的

    int i = 3;    //integer declaration
    int * pi = &i;    //pi points to the integer i
    int& ri = i;    //ri is refers to integer i – creation of reference and initialization
    

在此处输入图像描述

在此处输入图像描述

于 2018-03-13T12:43:18.407 回答
7

如果要修改变量的值,则应该传递一个指针。尽管在技术上传递引用或指针是相同的,但在您的用例中传递指针更具可读性,因为它“宣传”了值将被函数更改的事实。

于 2008-09-22T15:28:12.210 回答
5

如果您有一个可能需要指示缺少值的参数,通常的做法是将该参数设为指针值并传入 NULL。

在大多数情况下(从安全角度来看)更好的解决方案是使用boost::optional。这允许您通过引用传递可选值,也可以作为返回值。

// Sample method using optional as input parameter
void PrintOptional(const boost::optional<std::string>& optional_str)
{
    if (optional_str)
    {
       cout << *optional_str << std::endl;
    }
    else
    {
       cout << "(no string)" << std::endl;
    }
}

// Sample method using optional as return value
boost::optional<int> ReturnOptional(bool return_nothing)
{
    if (return_nothing)
    {
       return boost::optional<int>();
    }

    return boost::optional<int>(42);
}
于 2008-10-17T21:53:19.640 回答
5

尽可能使用引用,必要时使用指针。来自C++ FAQ:“什么时候应该使用引用,什么时候应该使用指针?”

于 2011-03-01T18:59:47.783 回答
3

引用是隐式指针。基本上,您可以更改引用指向的值,但不能更改引用以指向其他内容。所以我的 2 美分是,如果您只想更改参数的值,请将其作为引用传递,但如果您需要更改参数以指向不同的对象,请使用指针传递它。

于 2008-09-22T15:23:53.097 回答
3

考虑 C# 的 out 关键字。编译器要求方法的调用者将 out 关键字应用于任何 out args,即使它已经知道它们是否存在。这是为了提高可读性。尽管使用现代 IDE,我倾向于认为这是语法(或语义)突出显示的工作。

于 2008-10-17T22:22:19.550 回答
2

通过 const 引用传递,除非您有理由希望更改/保留您传入的内容。

在大多数情况下,这将是最有效的方法。

确保在您不想更改的每个参数上使用 const,因为这不仅可以防止您在函数中做一些愚蠢的事情,而且可以很好地向其他用户表明该函数对传入的值做了什么。这包括当您只想更改指向的内容时创建一个指针 const...

于 2008-09-22T11:43:55.497 回答
2

指针:

  • 可以赋值nullptr(或NULL)。
  • 在调用站点,&如果您的类型本身不是指针,则必须使用,明确表示您正在修改您的对象。
  • 三分球可以反弹。

参考:

  • 不能为空。
  • 一旦绑定,无法更改。
  • 调用者不需要显式使用&. 这有时被认为是不好的,因为你必须去函数的实现看看你的参数是否被修改。
于 2013-10-29T13:09:06.943 回答
0

引用类似于指针,不同之处在于您不需要使用前缀 * 来访问引用所引用的值。此外,在初始化后不能引用另一个对象。

引用对于指定函数参数特别有用。

有关更多信息,请参阅“Bjarne Stroustrup”(2014 年)第 11-12 页的“C++ 之旅”

于 2019-04-26T14:35:09.560 回答