C ++ Есть ли разница между присваиванием внутри передачи по значению и функции передачи по ссылке? - PullRequest
2 голосов
/ 22 марта 2010

Есть ли разница между foo и bar:

class A
{
  Object __o;

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

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

Насколько я понимаю, foo не выполняет операции копирования объекта o, когда он вызывается, и одну операцию копирования для назначения. Bar выполняет одну операцию копирования объекта o при его вызове, а другую - для назначения. Так что я могу более или менее сказать, что foo использует в 2 раза меньше памяти, чем bar (если o достаточно большой). Это правильно?

Возможно ли, что компилятор оптимизирует функцию bar для выполнения только одной операции копирования на o? то есть заставляет __o указывать на локальную копию аргумента o вместо создания новой копии?

Ответы [ 4 ]

6 голосов
/ 22 марта 2010

Это зависит. Например, если компилятор решит встроить функцию, очевидно, что копии не будет, поскольку нет вызова функции.

Если хотите быть уверенным, пройдите по const-reference:

void bar(const Object& o)

Это не делает копии. Обратите внимание, что ваша неконстантная версия требует lvalue, потому что ссылка изменяемая. foo(Object()) не будет работать, но временные значения (rvalues) могут быть связаны с константной ссылкой.


Кстати, двойные подчеркивания в идентификаторах зарезервированы для компилятора.

0 голосов
/ 22 марта 2010

Я думаю, что компиляторы могут выполнять оптимизацию в случае временных объектов.Этот метод называется копией elision.

Пожалуйста, обратитесь к ответам на вопрос, который я опубликовал Что такое копия, elision-and-how-it-optimizes-copy-and-swap-idiom .Это действительно полезно Что такое копирование и как оно оптимизирует идиому копирования и обмена?

Хотя я не эксперт в этом, насколько я понимаю, компиляторы могут оптимизироватькопирование временного объекта в некоторых сценариях.

Например, если ваш код называется так

bar(getObject())

, где getObject имеет подпись

Object getObject()

Этот вызовприведет к созданию временного типа Object.Если компилятор не выполняет какую-либо оптимизацию, временное значение должно быть скопировано в аргумент bar.

Однако, если компилятор поддерживает разрешение копирования, это копирование не будет выполнено, и временное будет передано в качестве аргумента bar функция.Таким образом, копия избегается, и ее производительность такая же, как у foo, которая принимает ссылку.Но, как я уже сказал, это происходит только в случае временного объекта

0 голосов
/ 22 марта 2010

Я считаю справедливым сказать, что foo() выполняет на одну копию меньше, чем bar(). Не имеет смысла говорить, сколько больше или меньше памяти используется, потому что для простых объектов они хранятся в стеке и очищаются после возврата из bar().

Как уже было сказано, не используйте подчеркивания в начале идентификаторов.

0 голосов
/ 22 марта 2010

Поскольку присваивание обычно принимает const Something& в качестве параметра, было бы канонично написать:

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

Но это не отвечает на ваш вопрос об оптимизации. Я не уверен, что в целом такая оптимизация может / будет выполнена компилятором.

...