Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Visual Studio is not creating temporary object when typecasting?

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.

like image 406
dnfs Avatar asked Feb 09 '15 03:02

dnfs


1 Answers

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.

like image 57
Shafik Yaghmour Avatar answered Oct 23 '22 08:10

Shafik Yaghmour