Rolf said:
SaltPeter said:
Something said:
I wrote some program
#include <iostream>
class A {
public:
A(void) { }
A(const A& t) { std::cout << "Good" << std::endl; }
};
A f(void) {
A t;
return t;
}
int main(int argc, char* argv[]) {
f();
return 0;
}
Why should the compiler copy by value an object of type A when the f()
discards it in main() above? Specifically, all the above code does is:
"call a function f() that constructs a temporary instance of A and
discards it"
No.
Function f() constructs a local instance of A and returns a copy of it.
If it had called the copy constructor, it should have printed "Good"
but it didn't.
Function f(void) does *not* construct a local instance of A.
It recognized t as a reference to the return value
and initializes the return value directly.
No "local" object of type A is ever created or destroyed.
Main() calls f() and then discards the returned value.
The important part is that main() is the one that discards the object,
not f().
That's a vacuous remark because function main(int, char**)
discards *all* local objects when it returns.
The actual reason for the copy constructor not being called
is probably the return value optimization
Named Return Value Optimization (NRVO)
that allows the compiler to avoid copying the object.
Try:
int main(int argc, char* argv[]) {
A a = f();
return 0;
}
That is likely to have the same effect.
An optimizing compiler might let main() specify the address of a to f(),
so that f() can construct the object directly into that memory
instead of first constructing it in its own local memory
and then copying it.
Also, to clarify what's happenning, and to emphasize that a copy
constructor is still a constructor, try:
class A {
public:
A(void) { std::cout << "cstor" << std::endl; }
~A(void) { std::cout << "dstor" << std::endl; }
A(const A& r_copy) { std::cout << "copy cstor" << std::endl; }
};
No it won't. All f(void) was asked to do is create a temporary object.
It can only return by value if it's given the opportunity to do so.
And what makes you think this is not the case?
The typical implementation emits nearly identical code for
#include <iostream>
class A {
public:
A(void) { }
A(const A& t) { std::cout << "Good" << std::endl; }
};
extern "C" {
A& f(A& value) {
value = A();
return value;
}
}
and
#include <iostream>
class A {
public:
A(void) { }
A(const A& t) { std::cout << "Good" << std::endl; }
};
extern "C" {
A f(void) {
A t;
return t;
}
}
When the typical C++ compiler parses
A a = f();
it emits code to allocate automatic storage for a
then it passes a reference to a to f(void)
as a *hidden* argument -- f(a) --
and function f(A&) initializes a directly.