tags:

views:

162

answers:

4

when ever a function has a object passed by value it uses either copy constructor or bit wise copy to create a temporary to place on stack to use inside the function,How about some object returned from function ?

//just a sample code to support the qn
rnObj somefunction()
{
return rnObj();
}

and also explain how the return value is taken to the called function.

+3  A: 

The C++ Standard states that the compiler can choose to create a temporary object, using the copy constructor, or it can choose to optimise away the temporary.

There is a wikipedia article on the subject, with numerous references here.

anon
can u explain more on how the return value is copied to destination location from stack
yesraaj
Note that the optimization is only permitted when you're initializing a named object with the return value. For example, { rnObj obj = somefunction(); } can be optimized, { functionThatTakesRnObj(somefunction()); } can't (correct me if I'm wrong). Another common mistake is to think that it can remove the overhead of assignment.
yesraaj: it isn't. Instead, "rnObj somefunction { return rnObj(); } int main() { rnObj obj = somefunction(); }" is implemented as something like "rnObj int main() { char buffer[sizeof(rnObj)]; rnObj } }"
... that is, assuming Return Value Optimization is performed. If it isn't, the copy constructor is used.
perhaps this would be better as an anaswer, rather than a comment?
anon
thanks for the reference article
yesraaj
+1  A: 

The compiler is allowed to perform a copy on return. Most compilers won't. You must, however, make sure that rnObj has an accessible copy constructor.

avakar
You are not required to provide a copy constructor.
anon
Neil, you're right of course, the compiler-generated copy-constructor is just fine. It was a poor choice of words. Fixed.
avakar
it is up to us to decide whether our class requires copy constructor or not..else compiler will use bitwise copy
yesraaj
yesraaj, if you don't provide a copy constructor, the compiler will generate one for you. It is not always possible, though, for example when one of the member objects is non-copyable.
avakar
avakar,you are rite
yesraaj
+1  A: 

Most modern compilers will be able to avoid the temporary object creation if the optimization is turned on. See Named Return Value Optimization for more details.

Naveen
+6  A: 

As can be judged by the other answers - the compiler can optimize this.

A concrete example generated using MSVC, to explain how this is possible (as asked in one of the comments) -

Take a class -

class AClass
{
public:
   AClass( int Data1, int Data2, int Data3 );

   int GetData1();

private:
   int Data1;
   int Data2;
   int Data3;
};

With the following trivial implementation -

AClass::AClass( int Data1, int Data2, int Data3 )
{
    this->Data1 = Data1;
    this->Data2 = Data2;
    this->Data3 = Data3;
}

int AClass::GetData1()
{
    return Data1;
}

And the following calling code -

AClass Func( int Data1, int Data2, int Data3 )
{
    return AClass( Data1, Data2, Data3 );
}

int main()
{
    AClass TheClass = Func( 10, 20, 30 );
    printf( "%d", TheClass.GetData1() );
}

(the printf() added just to make sure the compiler doesn't optimize everything away...).
In a non-optimized code, we would expect Func() to create a local AClass on its stack, construct it there and copy it as its return variable.

However, the generated assembly actually looks like (removing unneeded lines) -

_TEXT SEGMENT
___$ReturnUdt$ = 8   ; size = 4
_Data1$ = 12         ; size = 4
_Data2$ = 16         ; size = 4
_Data3$ = 20         ; size = 4

mov     eax, DWORD PTR _Data3$[esp-4]
mov     ecx, DWORD PTR _Data2$[esp-4]
mov     edx, DWORD PTR _Data1$[esp-4]
push    esi
mov     esi, DWORD PTR ___$ReturnUdt$[esp]
push    eax
push    ecx
push    edx
mov     ecx, esi
call    ??0AClass@@QAE@HHH@Z    ; AClass::AClass
mov     eax, esi
pop     esi
ret     0

The 3 function variables are extracted from the stack and placed into eax, ecx and edx.
Another forth value is placed into esi (and passed on to ecx).
The constructor is called with the 3 parameters on the stack, and ecx still containing the forth value.

Let's take a look in the constructor -

_TEXT SEGMENT
_Data1$ = 8    ; size = 4
_Data2$ = 12   ; size = 4
_Data3$ = 16   ; size = 4

mov    edx, DWORD PTR _Data2$[esp-4]
mov    eax, ecx
mov    ecx, DWORD PTR _Data1$[esp-4]
mov    DWORD PTR [eax], ecx
mov    ecx, DWORD PTR _Data3$[esp-4]
mov    DWORD PTR [eax+4], edx
mov    DWORD PTR [eax+8], ecx

ret    12   ; 0000000cH

The 3 constructor parameters are read into offsets of eax - eax being a copy of ecx, the forth parameter from the call above.
So, the constructor builts the object where it is told to - the forth parameter of Func().

And, you guessed it, the forth parameter of Func() is actually the real single place in the entire program where a constructed AClass exists. Let's look at the relevant part of main() -

_TEXT SEGMENT
_TheClass$ = -12    ; size = 12
_main PROC

sub    esp, 12

push   30
push   20
lea    eax, DWORD PTR _TheClass$[esp+20]
push   10
push   eax
call   ?Func@@YA?AVAClass@@HHH@Z    ; Func

12 bytes are reserved for an AClass and the three arguments to Func() are passed, along with the forth one - pointing to those 12 bytes.

This is a specific example with a specific compiler. Other compilers do this differently. But that's the spirit of things.

Hexagon