Non-Const Reference Bound to Temporary, Visual Studio Bug

Why can a non-const reference parameter be bound to a temporary object?

If you compile with the /Za option to disable language extensions, the compiler rejects both calls:

> cl /Za test.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x86
Copyright (C) Microsoft Corporation. All rights reserved.

test.cpp
test.cpp(11): error C2664: 'void f2(char &)' : cannot convert argument 1 from 'char' to 'char &'
test.cpp(12): error C2664: 'void f4(A &)' : cannot convert argument 1 from 'A' to 'A &'
A non-const reference may only be bound to an lvalue

There are several (very constrained) circumstances in which the compiler, with language extensions enabled, will still allow a non-const lvalue reference to bind to an rvalue expression. My understanding is that this is largely to avoid breaking several enormous legacy codebases that rely on this "extension."

(In general, use of /Za is not recommended for many reasons, but mostly because the Windows SDK headers cannot be #included with the /Za option.)

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.

How come a non-const reference cannot bind to a temporary object?

From this Visual C++ blog article about rvalue references:

... C++ doesn't want you to accidentally
modify temporaries, but directly
calling a non-const member function on
a modifiable rvalue is explicit, so
it's allowed ...

Basically, you shouldn't try to modify temporaries for the very reason that they are temporary objects and will die any moment now. The reason you are allowed to call non-const methods is that, well, you are welcome to do some "stupid" things as long as you know what you are doing and you are explicit about it (like, using reinterpret_cast). But if you bind a temporary to a non-const reference, you can keep passing it around "forever" just to have your manipulation of the object disappear, because somewhere along the way you completely forgot this was a temporary.

If I were you, I would rethink the design of my functions. Why is g() accepting reference, does it modify the parameter? If no, make it const reference, if yes, why do you try to pass temporary to it, don't you care it's a temporary you are modifying? Why is getx() returning temporary anyway? If you share with us your real scenario and what you are trying to accomplish, you may get some good suggestions on how to do it.

Going against the language and fooling the compiler rarely solves problems - usually it creates problems.



Edit: Addressing questions in comment:
1) `X& x = getx().ref(); // OK when will x die?` - I don't know and I don't care, because this is exactly what I mean by "going against the language". The language says "temporaries die at the end of the statement, unless they are bound to const reference, in which case they die when the reference goes out of scope". Applying that rule, it seems x is already dead at the beginning of the next statement, since it's not bound to const reference (the compiler doesn't know what ref() returns). This is just a guess however.

  1. I stated the purpose clearly: you are not allowed to modify temporaries, because it just does not make sense (ignoring C++0x rvalue references). The question "then why am I allowed to call non-const members?" is a good one, but I don't have better answer than the one I already stated above.

  2. Well, if I'm right about x in X& x = getx().ref(); dying at the end of the statement, the problems are obvious.

Anyway, based on your question and comments I don't think even these extra answers will satisfy you. Here is a final attempt/summary: The C++ committee decided it doesn't make sense to modify temporaries, therefore, they disallowed binding to non-const references. May be some compiler implementation or historic issues were also involved, I don't know. Then, some specific case emerged, and it was decided that against all odds, they will still allow direct modification through calling non-const method. But that's an exception - you are generally not allowed to modify temporaries. Yes, C++ is often that weird.

Assignment to non-const reference [duplicate]

The MSVC compiler has a non-standard extension, enabled by default, which allows temporaries to bind to non-const references. To disable this, use the command-line option /Za or the corresponding Project Property.

Do *non*-const references prolong the lives of temporaries?

The behavior hasn't changed, you just need to turn your warning level up to /W4. VisualStudio implements the lifetime extension rule even for non-const lvalue references as a compiler extension. In this context, binding an rvalue to the non-const reference behaves the same as if you were binding it to a const reference.

With /W4 you'd see this:

warning C4239: nonstandard extension used : 'initializing' : conversion from 'Foo' to 'Foo &'
1> A non-const reference may only be bound to an lvalue

The text disallowing binding of an rvalue to a non-const lvalue reference can be found in §8.5.3/5

— 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 ]

The second half of the quoted statement is what allows binding of a temporary to an rvalue reference, as shown in litb's answer.

string &&s = string("hello");

This, combined with the lifetime extension rule in §12.2/5, means the lifetime of the temporary will now match the lifetime of the (rvalue) reference it is bound to.

VS2010: Temporaries can't be bound to non-const references [duplicate]

Isn't call to fun producing a temporary?

Yes.

Why can temporary be linked to non-const reference here.

It can't.

I am unable to comprehend as to why is this compiling fine.

Because your compiler is faulty.

I am using VS2010. I don't understand how should this matter.

That compiler has many non-standard "extensions" to the language. This is just one example of dodgy code that's accepted by that compiler, but not a conformant one.

non-const lvalue reference type _normal_iterator cannot bind a temporary of type _normal iterator in gcc

begin does not return a reference. It returns an iterator, which is itself an object, by value. Therefore player_hands.begin(); is a temporary. Temporaries can not be bound to non-const lvalue references.

What you can do is either of the following:

auto hand_it = player_hands.begin(); 

const auto& hand_it = player_hands.begin();

auto&& hand_it = player_hands.begin();

What you should use is the first case. Although the lifetime of the temporary will be extended in the other two cases, there is no need to use references at all. The second case also limits the usability, because it makes the iterator const, making it impossible to e.g. hand_it++.

The iterator object itself refers to an element of the container. There is no need for references. A reference to the container element is obtained from the iterator with the indirection operator: *hand_it

Visual C++ is non-compliant with the standard in allowing binding of temporaries to non-const lvalue references. You can use the /permissive- flag to make it compliant and issue an error message for this code.

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), where T1 is not reference-related to T2, 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 ]



Related Topics



Leave a reply



Submit