views:

136

answers:

4

Is there a difference between foo and bar:

class A
{
  Object __o;

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

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

As I understand it, foo performs no copy operation on object o when it is called, and one copy operation for assignment. Bar performs one copy operation on object o when it is called and another one for assignment. So I can more or less say that foo uses 2 times less memory than bar (if o is big enough). Is that correct ?

Is it possible that the compiler optimises the bar function to perform only one copy operation on o ? i.e. makes __o pointing on the local copy of argument o instead of creating a new copy?

A: 

Since assignment typically takes const Something& as a parameter, it would be canonical to write:

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

But this does not answer your question about the optimization. I'm not sure that, in general, such optimization can / will be made by the compiler.

Daniel Daranas
+6  A: 

It depends. For example, if the compiler decides to inline the function, obviously there will be no copy since there is no function call.

If you want to be sure, pass by const-reference:

void bar(const Object& o)

This makes no copies. Note your non-const version requires an lvalue, because the reference is mutable. foo(Object()) wouldn't work, but temporaries (rvalues) can be bound to a const-reference.


Double-underscores in identifiers are reserved for the compiler, by the way.

GMan
"obviously there will be no copy" - assuming the copy ctor of `Object` has no observable effects it can be omitted. But this isn't a permitted case of copy elision, except when `bar` is called with a temporary as the parameter. In practice it might be omitted less often than you'd think for non-trivial classes. Consider `A a; Object *p = a.bar(*p);`. If the call was inlined and the copy omitted, then self-assignment would occur. Otherwise it wouldn't. So potentially the compiler has to inline quite a lot of code before it can tell whether those are "as-if" identical or not.
Steve Jessop
A: 

I think its fair to say that foo() performs one less copy than bar(). Its not very meaningful to say how much more or less memory is consumed, because for simple objects they are stored on the stack and cleaned up after return from bar().

As has been said, don't use underscores at the start of identifiers.

quamrana
A: 

I think compilers can do the optimization in case of temporary objects. This technique is called copy elision.

Please refer to the answers to question i had posted what-is-copy-elision-and-how-it-optimizes-copy-and-swap-idiom. This ans is really helpful http://stackoverflow.com/questions/2143787/what-is-copy-elision-and-how-it-optimizes-copy-and-swap-idiom/2143841#2143841

Though i am not an expert in this, from what i understand compliers can optimize copying of temporary object in some scenarios.

For example if your code is called like this

bar(getObject())

where getObject has a signature

Object getObject()

This call will result in creation of a temporary of type Object. If the compiler does not do any optimization that temporay has to be copied into the argument to bar.

However if compiler supports copy elision this copying wont be performed and the temporary will be passed as an argument to bar function. So the copy is avoided and its performance is same as foo which accepts a reference. But as i said it happens only in case of temporary object

Yogesh Arora
"copying wont be performed and the temporary will be passed as an argument to bar". To be more precise, if copy elision is performed then the "temporary" won't be created in memory in the first place. Instead, the return value from `getObject` will be constructed directly into the object (in practice: the position on the stack) which is the local variable `o` in `bar`.
Steve Jessop
thanks for clarifying
Yogesh Arora