I'm using Visual Studio Express 2013 and is fooling around a bit trying to learn about different things in C++.
I stumbled upon an interesting bug in the compiler where it doesn't seem to create a temporary object when explicitly type casting to the same type as the reference.
#include <iostream>
using namespace std;
int main()
{
int number; // float number;
number = 2;
const int& plainref_i = number;
const int& recastref_i = (int)number; // this goes wrong if number is int
const float& plainref_f = number;
const float& recastref_f = (float)number; // this goes wrong if number is float
number = 3;
std::cout << plainref_i << "\n";
std::cout << recastref_i << "\n";
std::cout << plainref_f << "\n";
std::cout << recastref_f << "\n";
return 0;
}
This will when compiled in VS, results in the following output:
3
3
2
2
But compiled with gcc, results in the following output:
3
2
2
2
If I replace "int number;" with "float number;" I get in VS:
2
2
3
3
and with gcc:
2
2
3
2
I'm wondering if anyone can confirm this as a bug and if anyone knows of a feasible workaround/solution.
Given:
int number;
The results of this cast should be a prvalue:
const int& recastref_i = (int)number; // this goes wrong if number is int
and since you are using const reference then it can bind to the prvalue and its value should be divorced from any changes to number
but Visual Studio has an extension which produces an lvalue instead of a prvalue, so you actually receive an lvalue reference to number
which means any changes in value to number
will be reflected when checking the value of recastref_i
.
The Visual Studio team recommends using the /Zc:rvalueCast
flag to turn off this behavior (emphasis mine):
When the /Zc:rvalueCast option is specified, the compiler correctly
identifies an rvalue reference type as the result of a cast operation
in accordance with the C++11 standard. When the option is not
specified, the compiler behavior is the same as in Visual Studio 2012.
By default, /Zc:rvalueCast is off. For conformance and to eliminate
errors in the use of casts, we recommend that you use /Zc:rvalueCast.
as opposed to /Za
which will disable all extensions which can be problematic in practical scenarios.
From the draft C++ standard section 5.4
Explicit type conversion (cast notation) paragraph 1 which says (emphasis mine):
The result of the expression (T) cast-expression is of type T. The
result is an lvalue if T is an lvalue reference type or an rvalue
reference to function type and an xvalue if T is an rvalue reference
to object type; otherwise the result is a prvalue.