【问题标题】:difference between a pointer and reference parameter?指针参数和引用参数的区别?
【发布时间】:2010-10-11 20:38:08
【问题描述】:

这些是一样的吗:

int foo(bar* p) {
  return p->someInt();
}

int foo(bar& r) {
  return r.someInt();
}

忽略潜在的空指针。无论someInt() 是虚拟的还是传递barbar 的子类,这两个函数在功能上是否相同?

这会切任何东西吗:

bar& ref = *ptr_to_bar;

【问题讨论】:

    标签: c++ pointers reference object-slicing


    【解决方案1】:

    标准中有意未指定 C++ 引用以使用指针实现。引用更像是变量的“同义词”,而不是指向它的指针。这种语义为编译器开启了一些可能的优化,当它可能意识到在某些情况下指针可能是一种过度杀伤力时。

    还有一些区别:

    • 您不能将 NULL 分配给引用。 这是一个关键的区别和 你更喜欢一个的主要原因 其他。
    • 当您获取地址时 指针,你得到的地址 指针变量。当你采取 参考地址,你得到 变量的地址是 参考。
    • 您无法重新分配参考。初始化后,它在整个生命周期中都指向同一个对象。

    【讨论】:

    • 您实际上可以将 NULL 分配给一个引用,如果您将其强制转换为该类型的指针,然后取消引用该点,例如int &ref = (int)NULL;如果将引用放在联合中并更改联合中的相应值,也可以重新分配引用。
    • 我应该补充一点,这些永远不应该这样做,因为当一个函数请求引用时,它不会期望 NULL,虽然大多数引用基本上与指针的实现方式相同,但这可能并非所有场景/平台都如此。
    • 如果您分配给联合的相应值,那么您并没有真正分配给引用,是吗?
    • 澄清将非 const 引用分配给 const 值(类似于 NULL,因为它是一个 const 宏定义值)是“不可能的”,这很有帮助。虽然在技术上可以通过低级操作进行此类操作,但不应在生产代码中完成。 C++11 有助于将 nullptr 作为一种类型引入并鼓励其普遍采用。
    【解决方案2】:

    忽略每个语法糖和可以用一个而不是另一个完成的可能性以及其他答案(其他问题)中解释的指针和引用之间的差异......是的,这两个在功能上完全相同!两者都调用函数并且都同样处理虚函数。

    不,你的线没有切片。它只是将引用直接绑定到指针指向的对象。

    关于为什么要使用一个而不是另一个的一些问题:

    我没有尝试自己提出差异,而是将您委托给那些您想知道的人。

    【讨论】:

      【解决方案3】:

      Reference 是一个常量指针,也就是说,您不能更改引用来引用其他对象。如果你改变了,引用对象的值就会改变。

      例如:

             int j = 10;
             int &i = j;
             int l = 20;
             i = l; // Now value of j = 20
      
             int *k = &j;
             k = &l;   // Value of j is still 10
      

      【讨论】:

        【解决方案4】:

        是的,它们在功能上是相同的。由于引用将要求您在使用它之前将其设置为对象,因此您不必处理空指针或指向无效内存的指针。

        看到语义差异也很重要:

        • 当您实际正常传递对象时使用引用 - 但它太大了,传递对对象的引用而不是制作副本更有意义(如果您不修改对象)。
        • 当您想处理内存地址而不是对象时,请使用指针。

        【讨论】:

          【解决方案5】:

          我已经很久没有使用C++了,所以我什至不会尝试真正回答你的问题(对不起);然而,Eric Lippert 刚刚发布了一个 excellent article 关于指针/引用的帖子,我想我会指给你看。

          【讨论】:

            【解决方案6】:

            不确定是否有人回答了隐藏在底部的关于切片的第二个问题......不,这不会导致切片。

            切片是指派生对象被分配(复制)给基类对象——派生类的特化被“切片”掉。请注意,我说 object 是被复制的,我们不是在谈论被复制/分配的指针,而是对象本身。

            在您的示例中,没有发生这种情况。您只是取消引用指向 Bar 对象的指针(从而导致 Bar 对象)在引用初始化中用作右值。不确定我的术语是否正确...

            【讨论】:

              【解决方案7】:

              正如其他人所提到的,在实现中引用和指针在很大程度上是相同的。有一些小警告:

              • 您不能将 NULL 分配给引用 (嘘提到这个):那是 显着,因为没有 “未定义”或“无效”引用 价值。

              • 您可以通过临时 变量作为 const 引用, 但是传递指针是不合法的 到一个临时的。

              例如,这没关系:

              class Thingy; // assume a constructor Thingy(int,int)
              void foo(const Thingy &a)
              { 
                 a.DoSomething();
              }
              
              void bar( ) 
              {
                foo( Thingy(1,2) );
              }
              

              但大多数编译器都会抱怨

              void foo2( Thingy * a);
              
              void bar2()
              {
                foo( &Thingy(1,2) );
              }
              
              • 使用变量的地址来获取指针会强制编译器将其保存到内存中。分配对局部变量的引用只会创建同义词;在某些情况下,这可能允许编译器将数据保留在寄存器上并避免load-hit-store。但是,这仅适用于局部变量——一旦通过引用将某些内容作为参数传递,就无法避免将其保存到堆栈中。

               

              void foo()
              {
                 int a = 5;
                 // this may be slightly more efficient
                 int &b = a;
                 printf( "%d", ++b );
                 // than this
                 int *c = &a;
                 printf( "%d", ++(*c) );
              }
              
              • 同样,__restrict keyword 不能应用于引用,只能应用于指针。

              • 你不能用引用做指针运算,所以如果你有一个指向数组的指针,那么数组中的下一个元素可以通过 p+1 获得,一个引用只指向一个东西它的整个生命。

              【讨论】:

                【解决方案8】:

                这些功能显然不是“相同的”,但就虚拟行为而言,它们的行为相似。关于切片,这只发生在处理值时,而不是引用或指针。

                【讨论】:

                • 实际上,它们可能会生成相同的机器代码,因此在这个意义上它们是相同的。
                猜你喜欢
                • 2014-04-21
                • 2011-07-04
                • 2011-06-17
                • 2021-02-02
                • 2012-03-22
                • 2011-09-22
                • 1970-01-01
                • 2015-02-07
                • 1970-01-01
                相关资源
                最近更新 更多