【问题标题】:Pass by reference using pointer and dereference pointer使用指针和解引用指针通过引用传递
【发布时间】:2014-05-06 07:23:34
【问题描述】:

哪个更好:通过引用传递使用void increment(int& x)通过指针传递使用void increment(int* x)

  1. void increment(int& x)
    {
        x=x+1;
    }
    int main()
    {  
        int n= 2;
        increment(n);
        cout << "Value of n is " << n << '\n';
        return 0;
    }
    

  2. void increment(int* x)
    {
        *x=*x+1;
    }
    int main()
    {  
        int n= 2;
        increment(&n);
        cout << "Value of n is " << n << '\n';
        return 0;
    }
    

【问题讨论】:

标签: c++ pass-by-reference pass-by-pointer


【解决方案1】:

没有比这更好的了。使用指针的优点是它在调用代码中明确表明参数是通过指针传递的,因为参数前面有&amp;。使用引用的好处是在调用函数代码中更加自然,不用全部*解引用。在内部通常以相同的方式实现,因此应该没有速度优势。

【讨论】:

    【解决方案2】:

    不知道你认为“更好”是什么意思,我只能说它们是不同的。

    通过引用传递的优点:

    1. 通过引用传递将阻止您传递nullptr,并使传递无效值变得更加困难。

    在性能方面,您不会看到太多差异(如果有的话)。

    指针传递的优点:

    1. 通过引用传递与 C 不兼容,因此如果您要公开希望从 C 调用的函数,则需要使其传递指针。

    2. 传递一个指针允许你传递nullptr/NULL。虽然将此列为一项好处似乎与将无法做到这一点列为引用的一项好处相矛盾,但这取决于您如何使用您的功能。如果您希望能够指定参数没有值(并且不想包含boost::optional 或自己滚动),那么指针是一种惯用的方式.

    在这种特定情况下,我更喜欢通过引用传递,因为没有理由在没有有效值的情况下调用函数。

    【讨论】:

      【解决方案3】:

      我个人的经验法则:

      • 对 (in/)out 参数使用指针,因此函数会立即更改变量
      • 对普通参数使用参考

      因此,在您的情况下,函数increment() 明显改变了传入的变量,我将使用指针。如果您使用引用,阅读您的代码的人将不得不跳转到函数的声明以了解函数的副作用。

      【讨论】:

        【解决方案4】:

        对于面向外部的组件(即在编写第三方将使用的库时),我会使用一个指针,它让用户知道您将修改他们传入的内容。这是以指针取消引用为代价的具有非常小的性能成本 - 因为您需要在使用它之前检查指针不是 NULL

        对于不打算公开的内部函数,通过引用传递是更可取的,因为它更容易编写并且(同样,只是稍微)性能更高。

        使用 clang 并且没有优化:

        00000000004004c0 <_Z10doThingRefRi>:
          4004c0:       48 89 7c 24 f8          mov    %rdi,-0x8(%rsp)
          4004c5:       48 8b 7c 24 f8          mov    -0x8(%rsp),%rdi
          4004ca:       8b 07                   mov    (%rdi),%eax
          4004cc:       05 01 00 00 00          add    $0x1,%eax
          4004d1:       89 07                   mov    %eax,(%rdi)
          4004d3:       c3                      retq
          4004d4:       66 66 66 2e 0f 1f 84    data32 data32 nopw %cs:0x0(%rax,%rax,1)
          4004db:       00 00 00 00 00
        
        00000000004004e0 <_Z10doThingPtrPi>:
          4004e0:       48 89 7c 24 f8          mov    %rdi,-0x8(%rsp)
          4004e5:       48 81 7c 24 f8 00 00    cmpq   $0x0,-0x8(%rsp)
          4004ec:       00 00
          4004ee:       0f 84 0f 00 00 00       je     400503 <_Z10doThingPtrPi+0x23>
          4004f4:       48 8b 44 24 f8          mov    -0x8(%rsp),%rax
          4004f9:       8b 08                   mov    (%rax),%ecx
          4004fb:       81 c1 01 00 00 00       add    $0x1,%ecx
          400501:       89 08                   mov    %ecx,(%rax)
          400503:       c3                      retq
          400504:       66 66 66 2e 0f 1f 84    data32 data32 nopw %cs:0x0(%rax,%rax,1)
          40050b:       00 00 00 00 00
        

        使用 clang 和 -O3

        00000000004004c0 <_Z10doThingRefRi>:
          4004c0:       ff 07                   incl   (%rdi)
          4004c2:       c3                      retq
          4004c3:       66 66 66 66 2e 0f 1f    data32 data32 data32 nopw %cs:0x0(%rax,%rax,1)
          4004ca:       84 00 00 00 00 00
        
        00000000004004d0 <_Z10doThingPtrPi>:
          4004d0:       48 85 ff                test   %rdi,%rdi
          4004d3:       74 02                   je     4004d7 <_Z10doThingPtrPi+0x7>
          4004d5:       ff 07                   incl   (%rdi)
          4004d7:       c3                      retq
          4004d8:       0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
          4004df:       00
        

        【讨论】:

        • “次要性能成本”?引用也必须被取消引用。事实上,大多数编译器都会在内部使用指针来实现引用。
        • 在使用引用取消引用之前,您不必检查 null 是成本的来源。我会用一些汇编程序编辑答案以指出这一点。
        • 如果你看这里:goo.gl/yGSy9s 在这两种情况下生成的汇编代码是相同的。所以不,没有性能差异。
        • 是 OP 代码的汇编器输出,还是您为指针添加了显式空检查?
        • 您的回答是“这是以取消引用指针为代价的,而这具有非常小的性能成本”,这是错误的。
        猜你喜欢
        • 1970-01-01
        • 2014-07-27
        • 2023-03-03
        • 2018-03-24
        • 1970-01-01
        • 1970-01-01
        • 2021-02-28
        • 1970-01-01
        相关资源
        最近更新 更多