 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
kwijibo28 Guest
|
Posted: Sat Dec 17, 2005 10:56 am Post subject: return by value question |
|
|
Hi all,
Please consider this piece of code.
class A
{
public:
A() {std::cout << "Default constructor" << std::endl;}
A(const A & _a) {std::cout << "Copy constructor" << std::endl;}
~A() {std::cout << "Destructor" << std::endl;}
};
A foo()
{
return A();
}
int main()
{
A a(foo());
return 0;
}
The output for this code is:
"Default constructor"
"Destructor"
If I change the foo() function to this:
A foo()
{
A a;
return a;
}
The output is:
"Default constructor"
"Copy constructor"
"Destructor"
"Destructor"
I was expecting this last behaviour for both cases. Is the first case a
compiler optimization or can I rely on it.
Thanks
Kwijibo
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Greg Herlihy Guest
|
Posted: Sun Dec 18, 2005 12:27 pm Post subject: Re: return by value question |
|
|
kwijibo28 wrote:
| Quote: | Hi all,
Please consider this piece of code.
....
A foo()
{
return A();
}
int main()
{
A a(foo());
return 0;
}
The output for this code is:
"Default constructor"
"Destructor"
If I change the foo() function to this:
A foo()
{
A a;
return a;
}
The output is:
"Default constructor"
"Copy constructor"
"Destructor"
"Destructor"
I was expecting this last behaviour for both cases. Is the first case a
compiler optimization or can I rely on it.
|
The second version of foo qualifies for the "named return value
optimization" (NRVO) because it satisfies two conditions: 1) the
variable that foo() returns is named 2) the variable that foo() returns
is always the same, named variable.
NRVO lets the compiler construct the result of a function call "in
place": meaning that the "a" variable in foo() is actually one and the
same with the "a" variable in main() (that is, the variable that holds
the result of the function call). NRVO is a particularly effective
optimization since it eliminates the copy operation that would
otherwise be needed when calling a function that returns its result by
value.
So to answer your question, yes this behavior is a compiler
optimization. So, no, as an optimization it cannot be relied on. And in
general, constructors should limit themselves to initializing the
object, and not take into consideration the "when" or the "why"'s of
the object's construction - since they could well vary.
Greg
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
puzzlecracker Guest
|
Posted: Sun Dec 18, 2005 12:28 pm Post subject: Re: return by value question |
|
|
kwijibo28 wrote:
| Quote: | Hi all,
Please consider this piece of code.
class A
{
public:
A() {std::cout << "Default constructor" << std::endl;}
A(const A & _a) {std::cout << "Copy constructor" << std::endl;}
~A() {std::cout << "Destructor" << std::endl;}
};
A foo()
{
return A();
}
int main()
{
A a(foo());
return 0;
}
The output for this code is:
"Default constructor"
"Destructor"
|
Dude, always remember that compiler optimize, unless you tell them
otherwise.
in this case, you ought to expect:
a. DC (default ctor)
b. C C (copy ctor, you copying into a temp)
c. Dtor( of the temp - a)
d. CC ( copying b into A a)
e. Dtor (for b)
| Quote: | If I change the foo() function to this:
A foo()
{
A a;
return a;
}
The output is:
"Default constructor"
"Copy constructor"
"Destructor"
"Destructor"
|
I am curious why copy ctor wasn't called in your case.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Victor Bazarov Guest
|
Posted: Sun Dec 18, 2005 12:30 pm Post subject: Re: return by value question |
|
|
kwijibo28 wrote:
| Quote: | Please consider this piece of code.
class A
{
public:
A() {std::cout << "Default constructor" << std::endl;}
A(const A & _a) {std::cout << "Copy constructor" << std::endl;}
~A() {std::cout << "Destructor" << std::endl;}
};
A foo()
{
return A();
}
int main()
{
A a(foo());
return 0;
}
The output for this code is:
"Default constructor"
"Destructor"
If I change the foo() function to this:
A foo()
{
A a;
return a;
}
The output is:
"Default constructor"
"Copy constructor"
"Destructor"
"Destructor"
I was expecting this last behaviour for both cases. Is the first case
a compiler optimization or can I rely on it.
|
If the last sentence is a question (actually, two), the answers are "yes"
and "no". An extraneous copying is allowed to be omitted, but the omission
is not mandated.
V
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Carl Barron Guest
|
Posted: Sun Dec 18, 2005 12:39 pm Post subject: Re: return by value question |
|
|
In article <1134761178.668855.20470 (AT) g49g2000cwa (DOT) googlegroups.com>,
kwijibo28 <kwijibo28 (AT) hotmail (DOT) com> wrote:
| Quote: | Hi all,
Please consider this piece of code.
class A
{
public:
A() {std::cout << "Default constructor" << std::endl;}
A(const A & _a) {std::cout << "Copy constructor" << std::endl;}
~A() {std::cout << "Destructor" << std::endl;}
};
A foo()
{
return A();
}
int main()
{
A a(foo());
return 0;
}
The output for this code is:
"Default constructor"
"Destructor"
If I change the foo() function to this:
A foo()
{
A a;
return a;
}
The output is:
"Default constructor"
"Copy constructor"
"Destructor"
"Destructor"
I was expecting this last behaviour for both cases. Is the first case a
compiler optimization or can I rely on it.
Its an optimization not requred by the standard. I would not count on |
it, if it happens its nice, but it if doesn't, its a copy ctor and
dtor call.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Viktor Prehnal Guest
|
Posted: Sun Dec 18, 2005 12:40 pm Post subject: Re: return by value question |
|
|
Hi,
I think it is some not good compiler optimization.
Have a look at my code, I have achieved even more MAGIC!!!!!!
Just notice that I do not copy variable a in copy constructor.
Works fine with VS.NET 2003 and VS.NET 2005.
#include "stdafx.h"
#include <iostream>
class A
{
public:
int a;
A(int ia = 0) {std::cout << "Default constructor" << std::endl; a =
ia; }
A(const A & _a) {std::cout << "Copy constructor" << std::endl;}
~A() {std::cout << "Destructor" << std::endl;}
};
A foo()
{
return A(5);
}
int main()
{
A a(foo());
std::cout << a.a << std::endl;
return 0;
}
Output:
Default Constructor
5
Destructor
Regards, Viktor
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Alberto Ganesh Barbati Guest
|
Posted: Mon Dec 19, 2005 10:19 am Post subject: Re: return by value question |
|
|
Viktor Prehnal wrote:
| Quote: | I think it is some not good compiler optimization.
Have a look at my code, I have achieved even more MAGIC!!!!!!
Just notice that I do not copy variable a in copy constructor.
Works fine with VS.NET 2003 and VS.NET 2005.
|
You (and puzzlecracker also) are advised to read carefully paragraph
12.8/15 in the C++ standard:
"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. [...]"
Notice the "even if" part. Whether this is a "good" or "bad"
optimization, I let you decide. As I don't usually write copy
constructors with degenerate behaviour like in your example, my personal
opinion leans towards the "good" side.
HTH,
Ganesh
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Alberto Ganesh Barbati Guest
|
Posted: Mon Dec 19, 2005 10:19 am Post subject: Re: return by value question |
|
|
kwijibo28 wrote:
| Quote: |
I was expecting this last behaviour for both cases. Is the first case a
compiler optimization or can I rely on it.
|
The first case is an optimization opportunity usually called RVO (Return
Value Optimization). This opportunity is described in the standard in
paragrap 12.8/15. About "relying" on it, it's the same argument as any
other optimization: you shouldn't do it.
Ganesh
PS: BTW the second case is called NRVO ("Named" Return Value
Optimization). The compiler is allowed to optimize (thus avoiding the
creation of the temporary) also in that case, but very few compiler
exploit this opportunity and yours falls is this category.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Bo Persson Guest
|
Posted: Mon Dec 19, 2005 10:22 am Post subject: Re: return by value question |
|
|
"Viktor Prehnal" <prehnal (AT) email (DOT) cz> skrev i meddelandet
news:do13na$21jt$1 (AT) ns (DOT) felk.cvut.cz...
| Quote: | Hi,
I think it is some not good compiler optimization.
Have a look at my code, I have achieved even more MAGIC!!!!!!
Just notice that I do not copy variable a in copy constructor.
Works fine with VS.NET 2003 and VS.NET 2005.
|
It seems to work, sometimes. :-)
How do you know that the output will not always be "5", if you have
only one test case?
In your example you can "optimize" even more, by removing the copy
constructor and destructor. The default versions generated buy the
compiler will work at least as well.
Bo Persson
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Greg Herlihy Guest
|
Posted: Mon Dec 19, 2005 10:22 am Post subject: Re: return by value question |
|
|
Viktor Prehnal wrote:
| Quote: | Hi,
I think it is some not good compiler optimization.
Have a look at my code, I have achieved even more MAGIC!!!!!!
Just notice that I do not copy variable a in copy constructor.
Works fine with VS.NET 2003 and VS.NET 2005.
#include "stdafx.h"
#include
class A
{
public:
int a;
A(int ia = 0) {std::cout << "Default constructor" << std::endl; a =
ia; }
A(const A & _a) {std::cout << "Copy constructor" << std::endl;}
~A() {std::cout << "Destructor" << std::endl;}
};
A foo()
{
return A(5);
}
int main()
{
A a(foo());
std::cout << a.a << std::endl;
return 0;
}
Output:
Default Constructor
5
Destructor
|
Assuming that you are using gcc, you can disable this optimization with
a -fno-elide-constructors switch. Compiling and running the program
with that option produces this output:
Default constructor
Copy constructor
Destructor
Copy constructor
Destructor
8
Destructor
(The "8" will vary - being the unitialized value of the member
variable "a")
Note that this version of the program does a lot more work than the
original. So the optimization is effective and assumes only that:
A a(A(5));
is equivalent to:
A a(5);
If such an equivalence does not hold then there is likely an
inconsistency in the program's object model. For example, leaving the
data member "a" uninitialized could not be considered correct. This
optimization therefore simply exposes a preexisting problem. In
general, as long as an object's copy and default constructors adhere to
a consistent model, then - whether copied or initialized - the
resulting object will be in a defined state.
Note also the Microsoft compilers probably do perform this optimization
when generating optimized code. It's possible that you only tested the
"debug" build in which most optimizations are disabled.
Greg
[Note that in my earlier post I called this optimization the Named
Return Value Optimization. Actually, it is the Return Value
Optimization that is being demonstrated.]
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kwijibo28 Guest
|
Posted: Mon Dec 19, 2005 10:39 am Post subject: Re: return by value question |
|
|
puzzlecracker wrote:
| Quote: | kwijibo28 wrote:
Hi all,
Please consider this piece of code.
class A
{
public:
A() {std::cout << "Default constructor" << std::endl;}
A(const A & _a) {std::cout << "Copy constructor" << std::endl;}
~A() {std::cout << "Destructor" << std::endl;}
};
A foo()
{
return A();
}
int main()
{
A a(foo());
return 0;
}
The output for this code is:
"Default constructor"
"Destructor"
Dude, always remember that compiler optimize, unless you tell them
otherwise.
in this case, you ought to expect:
a. DC (default ctor)
b. C C (copy ctor, you copying into a temp)
c. Dtor( of the temp - a)
d. CC ( copying b into A a)
e. Dtor (for b)
|
I must say I don't understand why you suggest that the copy constructor
must be called twice. You think there is a hidden temporary variable?
If three constructor are called shouldn't three destructor must be
called also?
kwijibo
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kwijibo28 Guest
|
Posted: Mon Dec 19, 2005 10:39 am Post subject: Re: return by value question |
|
|
I agree, this optimization can have serious side effect. In your
example, it breaks the program logic. I think I won't let the compiler
the chance to perform this optimization by writing my foo() function
like this:
A foo()
{
A a;
return a;
}
thanks
kwijibo
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Francis Glassborow Guest
|
Posted: Mon Dec 19, 2005 1:49 pm Post subject: Re: return by value question |
|
|
In article <1134964118.198270.155290 (AT) g44g2000cwa (DOT) googlegroups.com>,
kwijibo28 <kwijibo28 (AT) hotmail (DOT) com> writes
| Quote: | I agree, this optimization can have serious side effect. In your
example, it breaks the program logic. I think I won't let the compiler
the chance to perform this optimization by writing my foo() function
like this:
A foo()
{
A a;
return a;
I am not convinced that this makes any difference. The compiler has |
considerable latitude where copy construction is concerned. In effect it
assumes that a copy constructor simply provides a second copy if one is
needed and that a destructor simply destroys and object.
In the above code, a compiler is fully entitled to construct a directly
in the memory allocated for the return value.
In simple terms, you must not, in general, assume that side effects in
copy construction and destruction will occur and if your program relies
on these it is flawed.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Alberto Ganesh Barbati Guest
|
Posted: Tue Dec 20, 2005 12:46 am Post subject: Re: return by value question |
|
|
kwijibo28 wrote:
| Quote: | I agree, this optimization can have serious side effect. In your
example, it breaks the program logic. I think I won't let the compiler
the chance to perform this optimization by writing my foo() function
like this:
A foo()
{
A a;
return a;
}
|
Even in this case the compiler is allowed to optimize the copy away. The
only difference is that nowadays fewer compilers optimize so
aggressively. That might hopefully change in the future.
If you don't want this optimization, most compilers provide command-line
switches or pragmas to do that. You'd better use them instead of
changing your coding style.
However, I still don't understand what makes you so upset about this
optimization. It fits perfectly with my coding style, which makes it
very difficult to believe it would cause ill side-effects and, most
important, I find it beneficial. Of course, that's only my personal
opinion, but if the gurus put that in the standard, I believe I might be
in good company ;-)
Ganesh
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze Guest
|
Posted: Tue Dec 27, 2005 4:33 pm Post subject: Re: return by value question |
|
|
Francis Glassborow wrote:
| Quote: | In article
[email]1134964118.198270.155290 (AT) g44g2000cwa (DOT) googlegroups.com[/email]>,
kwijibo28 <kwijibo28 (AT) hotmail (DOT) com> writes
I agree, this optimization can have serious side effect. In
your example, it breaks the program logic. I think I won't
let the compiler the chance to perform this optimization by
writing my foo() function like this:
A foo()
{
A a;
return a;
I am not convinced that this makes any difference. The
compiler has considerable latitude where copy construction is
concerned. In effect it assumes that a copy constructor
simply provides a second copy if one is needed and that a
destructor simply destroys and object.
|
It might make a difference, for a given compiler and a given set
of compilation options. Or it might not.
I don't think enough insistance has been given to the fact that
in all of his examples, there is at least one copy that has been
optimized out. In both cases, the formal semantics of the
abstract machine imply two copies, one in the return statement,
and the second in the constructor in main. In both cases, the
compiler is given explicit authorisation to eliminate one or
both of the copies, by effectively merging what are formally two
separate objects.
| Quote: | In the above code, a compiler is fully entitled to construct a
directly in the memory allocated for the return value.
In simple terms, you must not, in general, assume that side
effects in copy construction and destruction will occur and if
your program relies on these it is flawed.
|
Which is the key to the problem. Even if the standard didn't
allow the optimizations, a normal reader will expect that a copy
constructor copies, and that if the object supports copying, one
copy more or less will not have any effects on the program's
correctness. The special authorizations which the standard
gives in these cases simply allow the compiler to make the same
assumptions as a normal reader would make. They can, of course,
cause misbehavior in intentionally obfuscated code, but I don't
think that support for obfuscation was a major design goal for
C++ (even if it sometimes seems that way:-)).
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|