2

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?

Rémy DAVID
  • 4,343
  • 6
  • 25
  • 27
  • 2
    On an unrelatd note: read this: http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier/228797#228797 – Martin York Mar 22 '10 at 15:11
  • 2
    Just a precaution: You should not rely on any kind of optimization (not) happening. Design your signature so that it expresses the semantics of what you want to achieve. – Björn Pollex Mar 22 '10 at 15:21
  • +1 for on emphasis on expressiveness – Yogesh Arora Mar 22 '10 at 15:23
  • 1
    Ouch, not just one underscore, but two? Are you *trying* to cause name clashes? **Never ever create a name containing double underscores in C++** – jalf Mar 22 '10 at 15:40
  • Duplicate: http://stackoverflow.com/questions/1567138/const-t-arg-vs-t-arg/1567186#1567186 – Alexey Malistov Mar 22 '10 at 16:03

4 Answers4

6

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.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • "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.__o); 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 Mar 22 '10 at 15:29
0

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
  • 22,454
  • 9
  • 63
  • 116
0

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
  • 37,849
  • 12
  • 53
  • 71
0

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 What is copy elision and how does it optimize the copy-and-swap idiom?

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

Community
  • 1
  • 1
Yogesh Arora
  • 2,216
  • 2
  • 25
  • 35
  • 1
    "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 Mar 22 '10 at 15:39