#include<iostream> using namespace std; struct B{}; struct A { A(const B &) { cout<<"A(const B &)"<<endl; } A(B &&) { cout<<"A(B &&)"<<endl; } }; A get() { B b; return b; } int main() { get(); }
I tested the code with VC++14.2 and GCC 5.4.0, both of them output:
A(B &&)
Why is the output not
A(const B &)
?
Does this code have any relation with copy elision
? (But A and B are different types, so copy elision
should not work here)
A copy constructor defines what copying means,So if we pass an object only (we will be passing the copy of that object) but to create the copy we will need a copy constructor, Hence it leads to infinite recursion. So, A copy constructor must have a reference as an argument.
Rvalue references is a small technical extension to the C++ language. Rvalue references allow programmers to avoid logically unnecessary copying and to provide perfect forwarding functions. They are primarily meant to aid in the design of higer performance and more robust libraries.
In C++11, however, the rvalue reference lets us bind a mutable reference to an rvalue, but not an lvalue. In other words, rvalue references are perfect for detecting whether a value is a temporary object or not.
A copy constructor is called when a new object is created from an existing object, as a copy of the existing object. The assignment operator is called when an already initialized object is assigned a new value from another existing object.
The return-as-rvalue rules changed in response to the review before publication of C++14. The change was added late in the process and is captured by CWG Issue 1579, that amends 12.8/32 with the wording:
or when the expression in a
return
statement is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body
This means that returning any local variable now considers the object designated by that variable as if it were an rvalue first (trying again if overload resolution fails).
Since the CWG issue was accepted as a defect in the language, compilers may implement this new rule even in "C++11 mode". The point of a defect is that "it was always meant to work that way", so this isn't strictly speaking a change between C++11 and C++14, but rather, the meaning of C++11 was modified in 2014.
Copy elision is related to A, not being constructed in the get() stack-frame. What happens is that the returned b
(that's temporary since "going to die because of return": this is since C++14), is use to construct the copy-elided A
in main stack-frame.
And since temporary objects binds r-value references that's what you observed.
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