469,160 Members | 1,965 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,160 developers. It's quick & easy.

C++ compiler "return" behavior (guru question ;)

Hi all,

I am trying to get my head around what happens if I return a class
object from a function.
It seems C++ (MinGW) does not invoke the copy constructor if I do
something like this:

SomeObj foo()
{
SomeObj X;
// ....
return X;
}

BUT it does create a new object every time the function is invoked, and
it does seem like these objects are usable (I created a little test
program checking this :).
So basically I can go in main:

int main()
{
// ....
SomeObj bar = foo();
SomeObj bar2 = foo();
// for some strange reason the next thing will fail, though:
SomeObj &bar3 = foo();
}

and I will get two different objects back, both valid. (As commented,
the third will fail with some obscure warning about temporary objects -
but there's no copying taking place, so there's no temp object, AFAIK).
Hm.

So I checked something else:

void foobar()
{
SomeObj IamUseless;
}

That object is actually constructed, but destroyed after the function.
Now I am a bit unsure how the C++ compiler can determine EACH TIME
which object gets returned (maybe in the depth of an STL container of
whatever), and which one does NOT, so this has to be destroyed.

Usually I use new() for factories, but I wondered, and I checked. And I
don't get it :) . So maybe there's a guru in here who can help me out
with some background information? ;)
Cheers & thanks,
Axel.

Apr 9 '06 #1
32 1841
Axel Bock wrote:
Hi all,

I am trying to get my head around what happens if I return a class
object from a function.
It seems C++ (MinGW) does not invoke the copy constructor if I do
something like this:

SomeObj foo()
{
SomeObj X;
// ....
return X;
}
The compiler is free to optimise away the redundant copy in this case.
BUT it does create a new object every time the function is invoked, and
it does seem like these objects are usable (I created a little test
program checking this :).
So basically I can go in main:

int main()
{
// ....
SomeObj bar = foo();
SomeObj bar2 = foo();
// for some strange reason the next thing will fail, though:
SomeObj &bar3 = foo();


You can't bind a temporary object (the function return) to a non-const
reference. Try

const SomeObj &bar3 = foo();

--
Ian Collins.
Apr 9 '06 #2
Hi Ian,

you're right, this works. But why should that return value be a const?
I have declared const nowhere in the whole thing, and there's no
copying between the return value and the used object in main. So I
would say the function's return value is in fact not a temporary
object, and it being const is ... weird. I can modify bar and bar2 all
right ... :)

Basically I wonder about the object created in foo(), because should be
on the stack, in my opinion, and should be destroyed after the
function's scope ends.

But thanks, that answers one question, although replacing it with
another ;)

cheers,
Axel.

Apr 9 '06 #3
Alex,
I hope this answers your question. When an object goes out of scope, it
is destroyed. This doesn't necessarily mean that the memory is erased,
but if you decide to use the object, the behavior is undefined. So
while the object may still be on the stack, there are no guarantees
that it won't be overwriten.

-matt

Apr 9 '06 #4
Axel Bock wrote:
Hi Ian,
Basically I wonder about the object created in foo(), because should be
on the stack, in my opinion, and should be destroyed after the
function's scope ends.

But thanks, that answers one question, although replacing it with
another ;)

cheers,
Axel.

Look for return value optimization.

SomeObj foo()
{
SomeObj X;
return X;
}
int main()
{
// ....
SomeObj bar = foo();
SomeObj bar2 = foo();
// for some strange reason the next thing will fail, though:
SomeObj &bar3 = foo();
}

The memory for bar and bar2 is allocated in main, and foo executes the
constructor for this object.
hth
Klaus

Apr 9 '06 #5
klaus hoffmann wrote:
Look for return value optimization.

SomeObj foo()
{
SomeObj X;
return X;
}


Is return value optimization allowed in this case? I thought it was
only possible for something like

SomeObj foo()
{
return SomeObj();
}

that is an unnamed object. Not sure though.

Apr 9 '06 #6
Markus Schoder posted:
klaus hoffmann wrote:
Look for return value optimization.

SomeObj foo()
{
SomeObj X;
return X;
}


Is return value optimization allowed in this case? I thought it was
only possible for something like

SomeObj foo()
{
return SomeObj();
}

that is an unnamed object. Not sure though.

Yes, it's allowed in both cases above. If the expression after "return" can
used as an l-value, then you're likely to see optimization. For instance:

SomeClassType foo()
{
SomeObj x;

return ++x; //Likely to see optimization
}

SomeClassType foo()
{
SomeObj x;

return x++; //Less likely to see optimization
}
-Tomás
Apr 9 '06 #7
Tomás wrote:
Markus Schoder posted:
klaus hoffmann wrote:
Look for return value optimization.

SomeObj foo()
{
SomeObj X;
return X;
}


Is return value optimization allowed in this case?


Yes, it's allowed in both cases above. If the expression after "return" can
used as an l-value, then you're likely to see optimization. For instance:

SomeClassType foo()
{
SomeObj x;

return ++x; //Likely to see optimization
}

SomeClassType foo()
{
SomeObj x;

return x++; //Less likely to see optimization
}


Checked this now in the Standard. According to 12.8 (15) your examples
both cannot be optimized but the original one (with just return x;) can
indeed. The expression in the return statement has to be the name of a
local object.

Apr 9 '06 #8
Hi all,

thanks for all the answers.
What I would like to clarify now is the "style" of that code: Is that
good style, or not?

I would rather say it's not, cause it surely LOOKS like a local object,
so using that is confusing. Maybe even compiler-dependent, for it is an
"optimization"? Anyways I do appreciate the ease of the assignment: To
have a function in which some init / creation / factory stuff can be
done, and assigning the return value without using copy constructors or
pointers. That on the other hand is good. Hm.

:-)

Anyways, cheers and thanks,
Axel.

Apr 10 '06 #9

Axel Bock wrote:
Hi all,

thanks for all the answers.
What I would like to clarify now is the "style" of that code: Is that
good style, or not?
It is good style.

I would rather say it's not, cause it surely LOOKS like a local object,
so using that is confusing.
But it IS a local object. I see nothing confusing about that. What
would be truly confusing would be if assignment created a different
object than copy construction.
Maybe even compiler-dependent, for it is an
"optimization"?
You might call it an optimization, but one employed by all compilers i
know. Still the optimization should not change anything for the reasons
stated above.
Anyways I do appreciate the ease of the assignment: To
have a function in which some init / creation / factory stuff can be
done, and assigning the return value without using copy constructors or
pointers. That on the other hand is good. Hm.


/Peter

Apr 10 '06 #10
Hi Peter,
But it IS a local object. I see nothing confusing about that. What
would be truly confusing would be if assignment created a different
object than copy construction.
Sorry to disagree, but I don't think this is a local object. What I
understand from what was said in the thread this object is available
globally (read: in main) after the function exits, and it is perfectly
legal in being so. So it _looks_ like one, but it is not destroyed
after scope exit, which makes it somewhat not-local in my eyes :) .
(Mind: I am talking about the _object_, not the C++-variable holding it
in the function).
You might call it an optimization, but one employed by all compilers i
know. Still the optimization should not change anything for the reasons
stated above.


Ok, that's a point, so this can be considered safe to use. Thanks :)
Cheers,
Axel.

Apr 10 '06 #11
Ian Collins wrote:
int main()
{
// ....
SomeObj bar = foo();
SomeObj bar2 = foo();
// for some strange reason the next thing will fail, though:
SomeObj &bar3 = foo();


You can't bind a temporary object (the function return) to a non-const
reference. Try

const SomeObj &bar3 = foo();


Wait, now I'm confused. Won't reading the value of bar3 yield
undefined behavior, since it references a temporary that went out of
scope?

Apr 10 '06 #12
What I would like to clarify now is the "style" of that code: Is that
good style, or not?


I think it's bad style to do the following:

SomeClassType object = FuncReturnsByValue();

For two reasons:

1) You must rely on an optimization if you don't want any copies.
2) The copy constructor must be public.

There are two workarounds. Here's the less favourable method:

std::auto_ptr<SomeClassType> Func()
{
std::auto_ptr<SomeClassType> p = new SomeClassType;

//Play with the object

return p;
}

int main()
{
std::auto_ptr<SomeClassType> p = Func();
}
The other option, the option which I advocate, is to use a class.

class Manipulator
{
SomeObj object;

Manipulator() : object( whatever )
{
//Play with the object in here
}
}

int main()
{
Manipulator manipulated;
}
-Tomás
Apr 10 '06 #13
Hi Tomas,

still, if you wanted a factory function, you should be able to write
one :) . Sometimes you want to create an object based on certain
external factors. If this action takes place in, say, 23 places in your
code, writing a function for that would be normal.

@Squeamizh: Confused is what I was. Still, as I understood, what we
face here is a so-called "return-value-optimization". In that case the
compiler recognizes that this object you return gets assigned to a ...
variable in the calling (!) code, so it will perform all the actions,
but the resulting object will be global. Or in other words: Doing a

SomeObj obj = foo();

translates to something like:

SomeObj &obj;
if (this_or_that) {
// .... yadda ....
obj = /* something smart */
}
else if (blah ...)
{
//.....
obj = /* whatever */
}
/* basically all your foo-code */

(very, very roughly) explained. And all this because the compiler
actually realizes that the _local_ object gets returned and is to be
used in a wider scope.

Apr 10 '06 #14
Squeamizh wrote:
Ian Collins wrote:
int main()
{
// ....
SomeObj bar = foo();
SomeObj bar2 = foo();
// for some strange reason the next thing will fail, though:
SomeObj &bar3 = foo();


You can't bind a temporary object (the function return) to a non-const
reference. Try

const SomeObj &bar3 = foo();

Wait, now I'm confused. Won't reading the value of bar3 yield
undefined behavior, since it references a temporary that went out of
scope?

Binding it to a const reference keeps it in scope.

--
Ian Collins.
Apr 10 '06 #15
Axel Bock wrote:
Hi Ian,

you're right, this works. But why should that return value be a const?
It isn't.
I have declared const nowhere in the whole thing, and there's no
copying between the return value and the used object in main.
There is copying. The compiler is allowed to perform an
optimization so it does not actually have to move bits around,
but the object management rules of C++ behave as if there is
a copy in all cases (it would be silly if legal code sometimes
worked and sometimes did not work based on whether a
compiler was optimizing or not).
So I would say the function's return value is in fact not a temporary
object,
The return value is a temporary object (aka. an rvalue). The fact that
the compiler may perform an optimization on it, does not change
anything.
and it being const is ... weird. I can modify bar and bar2 all
right ... :)
It isn't const. You can modify it. If you write:
foo().x = 3;
then there is no problem.

The original code was something like:
SomeObj const &bar3 = foo();

bar3 is a const reference. This means that you cannot modify
the referred-to object via this reference. The object itself is not
const.

Here's another example:

int i = 1;
int const &j = i;
j = 2; // illegal
i = 2; // legal

In this case 'i' is not const, even though there is a const
reference to it in existence.

Basically I wonder about the object created in foo(), because should
be on the stack, in my opinion, and should be destroyed after the
function's scope ends.


When you bind a temporary object to a reference, its lifetime
gets extended to match the scope of the reference (ie. the
object won't be destroyed until after the reference name goes
out of scope).

The rationale for not allowing binding non-const references to
temporary objects goes something like this:

void foo(int &i) { ++i; }

long x = 1;
foo(x);
cout << "x is " << x << endl;

You might expect this to output 2 but in fact it outputs 1.
There is no function foo() that takes a long, so the compiler
creates a temporary int which is initialized from x, and binds
this temporary int to 'i'. Then the temporary int is incremented,
and destroyed when foo() returns. The value of x is unchanged
by this. By banning binding of temporary objects to non-const
references, this situation would generate a compiler error.

Apr 10 '06 #16
On 10 Apr 2006 16:08:29 -0700, "Old Wolf" <ol*****@inspire.net.nz>
wrote:
The compiler is allowed to perform an
optimization so it does not actually have to move bits around,
but the object management rules of C++ behave as if there is
a copy in all cases (it would be silly if legal code sometimes
worked and sometimes did not work based on whether a
compiler was optimizing or not).


The compiler may elide copy constructor and destructor calls even if
they have side effects. In that case the C++ program behaves
differently dependent on the 'optimization', e.g.

class Test {
static int i;
public:
Test (const Test& t) {
++i;
}
// ...
};

The actual value of i is different when the the program is compiled
with RVO (and when RVO kicks in).
IMO, programs should return by value only 'leightweight' value objects
for which the 'savings' of RVO are irrelevant anyway.

Best wishes,
Roland Pibinger
Apr 11 '06 #17

Axel Bock wrote:
Hi Peter,
But it IS a local object. I see nothing confusing about that. What
would be truly confusing would be if assignment created a different
object than copy construction.


Sorry to disagree, but I don't think this is a local object. What I
understand from what was said in the thread this object is available
globally (read: in main) after the function exits, and it is perfectly
legal in being so. So it _looks_ like one, but it is not destroyed
after scope exit, which makes it somewhat not-local in my eyes :) .


Here is a cut down version of your original code

SomeObj foo()
{
SomeObj X;
return X;
}

int main()
{
SomeObj bar = foo();
}

You asked whether this was good style. Compilers don't care about style
- they only care about correctness. A compiler will accept poor style
exactly as readily as good style as long as the code is correct. It is
programmers who care about style.

So what does a programmer see in the above code snippet? There are two
completely separate objects of type SomeObj in the code. One is called
X and is local to the function foo. The other is called bar and is
local to the function main. X is destroyed at the end of foo. bar is
destroyed at the end of main. The programmer can perform SomeObj
operations on X within foo and can perform SomeObj operations on bar
within main. But X can not be accessed within main because it does not
exist there.

So what can a programmer do differently if they know return value
optimisation will be performed? Nothing. There is no code you can write
that would only be correct if return value optimisation were performed.
There is nothing you can write in main to violate the scoping rules
that apply to X and bar if the optimisation is performed. So there is
no problem with this style.

Gavin Deane

Apr 12 '06 #18
In message <11**********************@e56g2000cwe.googlegroups .com>, Axel
Bock <ax************@googlemail.com> writes
Hi Ian,
SomeObj bar = foo();
SomeObj bar2 = foo();const SomeObj &bar3 = foo();

you're right, this works. But why should that return value be a const?
The return value isn't; the reference is. You've tripped over an
arbitrary rule that says "thou shall not bind a temporary to a non-const
reference". It's arbitrary in the sense that deleting it wouldn't cause
inconsistencies elsewhere, but it's often a sign of a misunderstanding
or a coding error. So imposing the rule probably saves programmers from
more problems than it causes.
I have declared const nowhere in the whole thing, and there's no
copying between the return value and the used object in main.
There is (in effect, though it may not cause the copy constructor to be
called) a copy from the return value to the temporary object that the
reference is bound to.
So I
would say the function's return value is in fact not a temporary
object,
What's its name? If it doesn't have a name, it's temporary.
and it being const is ... weird.
You can always convert a non-const reference to a const one.
I can modify bar and bar2 all
right ... :)
Sure. They are named objects. But bar3 is just a reference to an unnamed
temporary that's about to evaporate. What would be the point of
modifying it? OK, sometimes it would make sense, but that's the
reasoning behind the rule.
Basically I wonder about the object created in foo(), because should be
on the stack, in my opinion, and should be destroyed after the
function's scope ends.

But thanks, that answers one question, although replacing it with
another ;)

cheers,
Axel.


--
Richard Herring
Apr 12 '06 #19
On 12 Apr 2006 04:41:13 -0700, "Gavin Deane" <de*********@hotmail.com>
wrote:
So what can a programmer do differently if they know return value
optimisation will be performed? Nothing. There is no code you can write
that would only be correct if return value optimisation were performed.
There is nothing you can write in main to violate the scoping rules
that apply to X and bar if the optimisation is performed. So there is
no problem with this style.


The problem is that you ignore possible side effects in the copy
constructor and the destructor.

Regards,
Roland Pibinger
Apr 12 '06 #20
The problem is that you ignore possible side effects in the copy
constructor and the destructor.


If the classes with which you are working were written "properly", then the
sideeffects of a copy-construction/destruction should be irrelevant. All
you should notice is that the execution time goes up on account of invoking
the copy constructor and subsequently, the destructor.
-Tomás

Apr 12 '06 #21
Hi all,

first of all thanks for all that information :) . But what I want to
clarify still is that _there is no copying taking place_.

In my logic, if an object gets copied, the copy constructor is used. I
implemented this one with a textual message, and this one gets never,
ever called. In the example that means that

SomeObj obj = foo();

does create an object in the foo() function, which will be assigned
directly to obj. No copying. Also it is the same object by pointer, I
compared the values. Hm.

Again: NO copying there. That's what irritated me.

:-) .
Cheers,

Axel.

Apr 13 '06 #22
In message <11**********************@v46g2000cwv.googlegroups .com>, Axel
Bock <ax************@googlemail.com> writes
Hi all,

first of all thanks for all that information :) . But what I want to
clarify still is that _there is no copying taking place_.

In my logic, if an object gets copied, the copy constructor is used. I
implemented this one with a textual message, and this one gets never,
ever called. In the example that means that

SomeObj obj = foo();

does create an object in the foo() function, which will be assigned
Not _assigned_. The assignment operator isn't used either.
directly to obj. No copying. Also it is the same object by pointer, I
compared the values. Hm.

Again: NO copying there. That's what irritated me.

:-) .
Cheers,

Axel.


--
Richard Herring
Apr 13 '06 #23
Axel Bock wrote:
Hi all,

first of all thanks for all that information :) . But what I want to
clarify still is that _there is no copying taking place_.

In my logic, if an object gets copied, the copy constructor is used. I
implemented this one with a textual message, and this one gets never,
ever called. In the example that means that

SomeObj obj = foo();

does create an object in the foo() function, which will be assigned
directly to obj. No copying. Also it is the same object by pointer, I
compared the values. Hm.

Again: NO copying there. That's what irritated me.


Here is some relevant language from the standard [12.8./15]:

When certain criteria are met, an implementation is allowed to omit the
copy construction of a class object, even if the copy constructor and/or
destructor for the object have side effects. In such cases, the
implementation treats the source and target of the omitted copy operation
as simply two different ways of referring to the same object, and the
destruction of that object occurs at the later of the times when the two
objects would have been destroyed without the optimization.111) This
elision of copy operations is permitted in the following circumstances
(which may be combined to eliminate multiple copies):

? in a return statement in a function with a class return type, when the
expression is the name of a non-volatile automatic object with the same
cv-unqualified type as the function return type, the copy operation can
be omitted by constructing the automatic object directly into the
function?s return value

? when a temporary class object that has not been bound to a reference
(12.2) would be copied to a class object with the same cv-unqualified
type, the copy operation can be omitted by constructing the temporary
object directly into the target of the omitted copy

[Example:
class Thing {
public:
Thing();
?Thing();
Thing(const Thing&);
};

Thing f() {
Thing t;
return t;
}

Thing t2 = f();

Here the criteria for elision can be combined to eliminate two calls to
the copy constructor of class Thing: the copying of the local automatic
object t into the temporary object for the return value of function f()
and the copying of that temporary object into object t2. Effectively, the
construction of the local object t can be viewed as directly initializing
the global object t2, and that object?s destruction will occur at program
exit. ?end example]
Best

Kai-Uwe Bux
Apr 13 '06 #24

Roland Pibinger wrote:
On 12 Apr 2006 04:41:13 -0700, "Gavin Deane" <de*********@hotmail.com>
wrote:
So what can a programmer do differently if they know return value
optimisation will be performed? Nothing. There is no code you can write
that would only be correct if return value optimisation were performed.
There is nothing you can write in main to violate the scoping rules
that apply to X and bar if the optimisation is performed. So there is
no problem with this style.


The problem is that you ignore possible side effects in the copy
constructor and the destructor.


That's a different point. I was addressing the OP's apparent concern
that there is something somehow unsafe about return value optimisation.

Your point is only a problem if you write copy constructors and
destructors with side effects. *If* you do that, *and* it is necessary
that the side effects happen, clearly you must avoid using objects of
that type in any situation where the language allows temporary copies
to be elided. Depending on the particular situation, a rethink of the
design may be a better long-term solution.

Gavin Deane

Apr 13 '06 #25

Axel Bock skrev:
Hi all,

first of all thanks for all that information :) . But what I want to
clarify still is that _there is no copying taking place_.
Right. The standard says so, so it should not be to surprising.
In my logic, if an object gets copied, the copy constructor is used. I
implemented this one with a textual message, and this one gets never,
ever called. In the example that means that

SomeObj obj = foo();

does create an object in the foo() function, which will be assigned
directly to obj. No copying. Also it is the same object by pointer, I
compared the values. Hm.
First of all, the fact that you did notice in the first place is what
should really worry you. This means that you use the assignment
operator for something that is not assignment. While this technically
is legal it is confusing in the same way as if you used operator+ to do
division,
Secondly, I wonder (wearing my technical glasses) how you can be so
sure that it is the same object. That they have the same adress does
not imply they are equal. Memory IS allowed to be reused, you know -
much to the discontent of the RAM-producers.

/Peter
Again: NO copying there. That's what irritated me.

:-) .
Cheers,

Axel.


Apr 13 '06 #26
The following code calls a constructor and a destructor.

void fn1 (void)
{
Object obj;
}

The following code has a constructor call for the local object, followed
by a copy constructor for the return, and then a destructor for the
local object.

Object fn2 (void)
{
Object obj;
return obj;
}

The following code has a constructor call, followed by a copy constructor.

Object fn3 (void)
{
return *new Object; // "bad" style :)
}

In fn2 the compiler is allowed to omit the copy by constructing the
object "in-place" of the return value; in MSVC this is accomplished by
passing in the address to construct the object. This is a desirable
effect.
Apr 13 '06 #27
On Thu, 13 Apr 2006 05:28:02 -0400, Kai-Uwe Bux <jk********@gmx.net>
wrote:
Here is some relevant language from the standard [12.8./15]:

When certain criteria are met, an implementation is allowed to omit the
copy construction of a class object, even if the copy constructor and/or
destructor for the object have side effects.


It's astonishing that Stroustrup let that slip into the language.
Apr 13 '06 #28
Roland Pibinger posted:
When certain criteria are met, an implementation is allowed to omit
the copy construction of a class object, even if the copy constructor
and/or destructor for the object have side effects.


It's astonishing that Stroustrup let that slip into the language.

I disagree entirely -- I think it paves the way for more efficient
programming.

If a class has "side effects" because of a copy constructor or destructor,
then it's a stupid class.

-Tomás
Apr 14 '06 #29
Tomás wrote:
Roland Pibinger posted:
When certain criteria are met, an implementation is allowed to omit
the copy construction of a class object, even if the copy constructor
and/or destructor for the object have side effects.
It's astonishing that Stroustrup let that slip into the language.

I disagree entirely -- I think it paves the way for more efficient
programming.


I also think RVO is a win.
If a class has "side effects" because of a copy constructor or destructor,
then it's a stupid class.


Maybe true for the copy constructor for the destructor however side
effects are not uncommon the whole RAII concept cannot work without
them (think std::fstream or classes for mutex locking). Of course these
are not objects you would normally return from a function.

Apr 14 '06 #30
"Markus Schoder" <a3*************@yahoo.de> wrote in message
news:11**********************@i40g2000cwc.googlegr oups.com...
:Tomás wrote:
:> Roland Pibinger posted:
:>
:> >> When certain criteria are met, an implementation is allowed to omit
:> >> the copy construction of a class object, even if the copy
constructor
:> >> and/or destructor for the object have side effects.
:> >
:> > It's astonishing that Stroustrup let that slip into the language.
:>
:>
:> I disagree entirely -- I think it paves the way for more efficient
:> programming.
:
:I also think RVO is a win.
:
:> If a class has "side effects" because of a copy constructor or
destructor,
:> then it's a stupid class.
:
:Maybe true for the copy constructor for the destructor however side
:effects are not uncommon the whole RAII concept cannot work without
:them (think std::fstream or classes for mutex locking). Of course these
:are not objects you would normally return from a function.

One may want "RAII"-style objects to be returned from functions,
if ownership-transfer semantics are implemented.
Think of std::auto_ptr
Of course, the latter is a bit of a hack in the current C++ standard,
but better support for the concept may soon be integrated in the
core language (look for proposals related to r-value references, the
latest version of which can be found here:
http://www.open-std.org/jtc1/sc22/wg...006/n1952.html ).

Ivan
--
http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form

Apr 14 '06 #31

Axel Bock skrev:
Hi Tomas,
[snip] @Squeamizh: Confused is what I was. Still, as I understood, what we
face here is a so-called "return-value-optimization". In that case the
compiler recognizes that this object you return gets assigned to a ...
variable in the calling (!) code, so it will perform all the actions,
but the resulting object will be global. Or in other words: Doing a

SomeObj obj = foo();

translates to something like:

SomeObj &obj;
if (this_or_that) {
// .... yadda ....
obj = /* something smart */
}
else if (blah ...)
{
//.....
obj = /* whatever */
}
/* basically all your foo-code */

(very, very roughly) explained. And all this because the compiler
actually realizes that the _local_ object gets returned and is to be
used in a wider scope.

What happens in practice whenever an object is returned from a function
is that the caller supplies memory for the returned object. Thus

SomeObj func()
{
SomeObj res;
...
returm res;
}

gets translated to

void func(void* area_suitable_for_SomeObj).
{
SomeObj res;
...
new (area_suitable_for_SomeObj) SomeObj(res);
}

Now, return value-optimisation allows the function above to be
implemented as:
void func(void* area_suitable_for_SomeObj).
{
new (area_suitable_for_SomeObj) SomeObj();
...
}

Notice that all functions that return an object will normally follow
the path above - irrespective of language. Pascal would do it the same
way. It is only when the object returned is small enough to fit into a
(few) register, that this way of passing is not used.

/Peter

Apr 14 '06 #32
I see. Thanks a lot for that clarification! I now understand why is
happening what is happening ;)

cheers,
Axel.

Apr 14 '06 #33

This discussion thread is closed

Replies have been disabled for this discussion.

By using this site, you agree to our Privacy Policy and Terms of Use.