【问题标题】:C++ is there a difference between assignment inside a pass by value and pass by reference function?C ++在按值传递和按引用函数内传递之间有区别吗?
【发布时间】:2011-01-30 09:31:16
【问题描述】:

foo和bar有区别吗:

class A
{
  Object __o;

  void foo(Object& o)
  {
    __o = o;  
  }

  void bar(Object o)
  {
    __o = o;
  } 
} 

据我了解, foo 在调用对象 o 时不会对它执行复制操作,而对分配执行一次复制操作。 Bar 在被调用时对对象 o 执行一个复制操作,另一个用于赋值。所以我或多或少可以说 foo 使用的内存比 bar 少 2 倍(如果 o 足够大的话)。对吗?

编译器是否可以优化 bar 函数以仅对 o 执行一次复制操作?即使 __o 指向参数 o 的本地副本而不是创建新副本?

【问题讨论】:

标签: c++ reference variable-assignment


【解决方案1】:

我认为编译器可以在临时对象的情况下进行优化。这种技术称为复制省略。

请参阅我发布的问题的答案what-is-copy-elision-and-how-it-optimizes-copy-and-swap-idiom。这个答案真的很有帮助What is copy elision and how does it optimize the copy-and-swap idiom?

虽然我不是这方面的专家,但据我了解,编译器可以在某些情况下优化临时对象的复制。

例如,如果您的代码是这样调用的

bar(getObject())

getObject 有签名的地方

Object getObject()

此调用将导致创建Object 类型的临时对象。如果编译器不做任何优化,则必须将 temporay 复制到 bar 的参数中。

但是,如果编译器支持复制省略,则不会执行此复制,并且临时将作为参数传递给 bar 函数。因此避免了复制,其性能与接受引用的foo 相同。但正如我所说,它只发生在临时对象的情况下

【讨论】:

  • "不会执行复制,临时将作为参数传递给 bar"。更准确地说,如果执行复制省略,那么“临时”将不会首先在内存中创建。相反,getObject 的返回值将直接构造到对象中(实际上是堆栈上的位置),即bar 中的局部变量o
【解决方案2】:

我认为 foo() 执行的副本比 bar() 少一份是公平的。说消耗多少内存并没有多大意义,因为对于简单的对象,它们存储在堆栈中,并在从bar()返回后清理。

如前所述,不要在标识符的开头使用下划线。

【讨论】:

    【解决方案3】:

    这取决于。例如,如果编译器决定内联函数,显然不会有副本,因为没有函数调用。

    如果你想确定,通过 const-reference 传递:

    void bar(const Object& o)
    

    这不会产生副本。请注意,您的非常量版本需要左值,因为引用是可变的。 foo(Object()) 不起作用,但临时变量(右值)可以绑定到 const 引用。


    顺便说一下,标识符中的双下划线是为编译器保留的。

    【讨论】:

    • "显然不会有副本" - 假设 Object 的副本 ctor 没有可观察到的效果,它可以省略。但这不是复制省略的允许情况,除非使用临时参数作为参数调用 bar。在实践中,它可能被省略的频率低于你对非平凡类的想象。考虑A a; Object *p = &(a.__o); a.bar(*p);。如果调用是内联的并且省略了副本,则会发生自分配。否则不会。因此,编译器可能必须内联大量代码才能判断它们是否“好像”相同。
    【解决方案4】:

    由于赋值通常将const Something& 作为参数,因此可以这样写:

      void foo(const Object& o)
      {
        __o = o;  
      }
    

    但这并不能回答您关于优化的问题。我不确定,一般来说,这种优化可以/将由编译器进行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-19
      • 1970-01-01
      • 2020-04-10
      • 2019-02-10
      • 2012-05-22
      • 2012-07-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多