One VS2010 bug ? Allowing binding non-const reference to rvalue WITHOUT EVEN a warning?
That is a known issue/feature of the VS compilers. They have always allowed that and there does not seem to be any push into removing that extension.
Is it valid to bind non-const lvalue-references to rvalues in C++ 11?(modified)
should that work in c++11?
No, it should not.
Foo
is a custom class, I don't understand why the first two line compiles
It compiles only with MSVC. MSVC has an (arguably useful) compiler extension that allows binding lvalues of user-defined types to rvalues, but the Standard itself forbids this. See, for instance, this live example where GCC 4.7.2 refuses to compile your code.
Does the standard say anything about this?
Indeed it does. Per paragraph 8.5.3/5 of the C++11 Standard:
A reference to type “
cv1 T1
” is initialized by an expression of type “cv2 T2
” as follows:— If the reference is an lvalue reference and the initializer expression
— is an lvalue (but is not a bit-field), and “
cv1 T1
” is reference-compatible with “cv2 T2
,” or
— has a class type (i.e.,
T2
is a class type), whereT1
is not reference-related toT2
, and can be
implicitly converted to an lvalue of type “cv3 T3
,” where “cv1 T1
” is reference-compatible with “cv3
” [...],
T3
then the reference is bound to the initializer expression lvalue in the first case and to the lvalue result
of the conversion in the second case (or, in either case, to the appropriate base class subobject of
the object). [...][ ...]
— Otherwise, the reference shall be an lvalue reference to a non-volatile const type (i.e., cv1 shall be
const), or the reference shall be an rvalue reference. [ Example:double& rd2 = 2.0; // error: not an lvalue and reference not const
int i = 2;
double& rd3 = i; // error: type mismatch and reference not const
—end example ]
non-const reference to rvalue
What I don't understand is why does the
temp1.foo_ref(temp())
succeed.
Judging by use of void main() { ... }
, you must have an old or non-standards compliant compiler.
temp1.foo_ref(temp());
should fail. I get the following error using g++ 4.8.4.
g++ -Wall -std=c++11 socc.cc -o socc
socc.cc: In function ‘int main()’:
socc.cc:13:22: error: no matching function for call to ‘temp::foo_ref(temp)’
temp1.foo_ref(temp()); //foo_ref (temp& a) is called
^
socc.cc:13:22: note: candidate is:
socc.cc:6:7: note: void temp::foo_ref(temp&)
void foo_ref(temp& a){}
^
socc.cc:6:7: note: no known conversion for argument 1 from ‘temp’ to ‘temp&’
error related to binding non-const lvalue to rvalue in constructor
The problem is the following, you are creating a temporary
make_shared<X>(NULL)
that will die after the line is executed, and the reference in your class will be dangling (i.e. referencing something that has been destroyed), if you try to access the reference you will be in undefined behavior territory (your program can crash, or worse continue in a corrupted state).
A way to fix it would be to not use references to shared_ptr
but directly shared_ptr
in all your classes which is way safer.
Secondly, you might want to use nullptr
instead of NULL
Lastly, I think you are misunderstanding what the references are supposed to do: they are not about ownership of a resource, but simply allow access to a resource, when you have a reference to something you must be sure that somebody else is keeping that resource alive for as long as you want to access the resource via the reference (there is an exception: lifetime extension via a local const ref, see https://blog.galowicz.de/2016/03/23/const_reference_to_temporary_object/).
Why rvalue reference as return type can't be initialization of non-const reference?
I know that an rvalue reference is an lvalue.
You're talking about two different things: type and value category. e.g.
int&& ri = 0; // ri's type is rvalue reference (to int)
// ri's value category is lvalue; it's a named variable.
Given your 1st sample, what fun()
returns is an xvalue, which belongs to rvalues.
The following expressions are xvalue expressions:
- a function call or an overloaded operator expression, whose return type is rvalue reference to object, such as
std::move(x)
;
then,
int &a = fun(); // fails; lvalue-reference can't bind to rvalue
In the 2nd sample, what fun()
returns is an lvalue,
The following expressions are lvalue expressions:
- a function call or an overloaded operator expression, whose return type is lvalue reference, such as
std::getline(std::cin, str)
,std::cout << 1
,str1 = str2
, or++it
;
then
int & a=fun(); // fine; lvalue-reference could bind to lvalue
In the 3rd sample,
decltype(fun()) b = 1; // the return type of fun() is rvalue-reference;
// this has nothing to do with the value category of its return value
// b's type is rvalue-reference too, btw its value category is lvalue
In the 4th sample,
int &&a = 1; // fine; rvalue-reference could bind to rvalue
// a's type is rvalue-reference, its value category is lvalue
int &b = a; // fine; lvalue-reference could bind to lvalue
// b's type is lvalue-reference, its value category is lvalue
error: cannot bind non-const lvalue reference of type ‘Position&’ to an rvalue of type ‘Position’
Your update()
is looking to take a Position
by reference so that it can make modifications and have them percolate back to the object you're passing. However, tortoise->getCurrPos()
returns a Position
copy. If you want the changes in update()
to affect your tortoise
's Position
member, you'll need to have getCurrPos()
return its Position
by reference.
Position Runner::getCurrPos() {
Should become
Position& Runner::getCurrPos() {
For more, you can read up at What is a reference variable in C++?
Allowed to bind an rvalue to a non-const lvalue reference?
This is a compiler "extension" (or "bug", depending on your perspective) of the Microsoft compiler. C++ only allows non-const binding of an lvalue to a non-const lvalue reference.
std::tie fails with cannot bind non-const lvalue reference when passed value from a function call
std::tie
takes lvalue references as arguments, so int
returned by S::y
can't bind. You could use the perfect forwarding version, std::forward_as_tuple
, instead:
#include <tuple>
struct S
{
int x = 0;
int y() const { return 1; }
};
bool f(const S& a, const S& b)
{
return std::forward_as_tuple(a.x, a.y()) < std::forward_as_tuple(b.x, b.y());
}
Demo.
Related Topics
What Is the Default Constructor for C++ Pointer
Array Initialization Use Const Variable in C++
Concatenate Two String Literals
Redirect Stdout/Stderr to a String
C++ System() Not Working When There Are Spaces in Two Different Parameters
Efficient 128-Bit Addition Using Carry Flag
Error When Compiling Some Simple C++ Code
How to Get a "Useful" C++ Binary Search Algorithm
What Is Shared_Ptr's Aliasing Constructor For
Extending the C++ Standard Library by Inheritance
How Is the Size of a C++ Class Determined
Is the Behaviour of I = I++ Really Undefined
Difference Between *(Pointer + Index) and Pointer[]
Porting Clock_Gettime to Windows
Long Long Int VS. Long Int VS. Int64_T in C++
How to Build an Import Library (.Lib) and a Dll in Visual C++