Please consider the following code,
struct foo
{
foo()
{
std::cout << "Constructing!" << std::endl;
}
foo(const foo& f)
{
std::cout << "Copy constructing!" << std::endl;
}
~foo()
{
std::cout << "Destructing.." << std::endl;
}
};
foo get()
{
foo f;
return f;
}
int main()
{
const foo& f = get();
std::cout << "before return" << std::endl;
return 0;
}
Output on MSVC
Constructing!
Copy constructing!
Destructing..
before return
Destructing..
Output of GCC
Constructing!
before return
Destructing..
The result which comes on MSVC looks incorrect.
Questions
const foo& f = get()
and const foo f = get()
produces same output because of return value optimization. In this case, which way of writing should be preferred?Any thoughts..
Not just a copy; it is also a const copy. So you cannot modify it, invoke any non-const members from it, or pass it as a non-const parameter to any function. If you want a modifiable copy, lose the const decl on protos .
When we create our own copy constructor, we pass an object by reference and we generally pass it as a const reference. One reason for passing const reference is, we should use const in C++ wherever possible so that objects are not accidentally modified.
C does not support references or passing by reference. You should use pointers instead and pass by address. Pass-by-value is efficient for primitive types, but does a shallow copy for structs. In C++ it makes a LOT of sense to pass objects by reference for efficiency.
The grammar doesn't allow you to declare a “const reference” because a reference is inherently const . Once you bind a reference to refer to an object, you cannot bind it to refer to a different object.
Your MSVC build has no optimizations on. Turn them on, you'll get identical output for both.
GCC is merely performing, by default, RVO on your temporary. It's basically doing:
const foo& f = foo();
MSVC is not. It's making the foo
in the function, copying it to the outside the function (ergo the copy-constructor call), destructing the inner foo
, then binds the reference.
Both outputs are correct. RVO is one instance where the standard explicitly allows the observable behavior of the program to change.
You are seeing the return value optimization, which is one kind of copy elision. Both programs are correct; the compiler is specifically given the option of eliminating a temporary which only serves to move data from one permanent object to another.
The get() function is Constructing the local (print Constructing!), and returning a Foo object by value. The Foo object being returned must be created and is done so via copy construction (print Copy constructing!). Note that this is the object value assigned to the const foo & f in main.
Before that assignment takes place though, the function must return from get() and local variables (i.e. foo f; in get()) must be destroyed. (print 1st Destructing..) From there the program terminates (i.e. returns from main) then the object returned by get() and assigned to "f" is destroyed. (print 2nd Destructing...)
The reason you're seeing different output for the two compilers is that GCC is optimizing the return value for get() and is simply replacing const foo &f = get()
to const foo &f = foo
;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With