What are the consequences of ignoring narrowing conversions in C++0x
Asked Answered
P

1

9

Since switching on the C++0x standard in g++, I've started seeing 'narrowing conversion' errors, particularly when converting from an 'int' to a 'short' although I understand the error covers a much broader swath of conversions.

Can anyone shed some light on the rational for introducing this extra level of safety?, What are the possible consequences of disabling this error? (apart from the potential loss of precision).

Thanks.

Pancreas answered 20/12, 2011 at 16:39 Comment(5)
Your rocket could explodeDissatisfied
If I ever work on a rocket, I'll be sure to keep that in mind ;)Pancreas
This is something that has produced warnings always, forever, and forever and a day, and it's a good thing. Now it's an error, it's debatable whether that is a good thing since it breaks compilation of existing, presumably correct, code. However, it prevents some impossible to track errors, so I can see the rationale. I wouldn't disable such an error logic, because when you accidentially throw away the upper half of a value and they have a meaning, your code still works just fine until it doesn't, and then you don't know why.Bumgardner
Imagine for example an API function which checks for an (unsigned) -1 error code, and you truncate the binary value 0xffffffff to 0x0000ffff. Or imagine a loop that will run forever because the exit condition can never be true. Or worse, a loop that will sometimes run forever, if some particular user input causes such a problem. You'll never find out why.Bumgardner
Damon, flesh out an answer to that effect and I'll accept it.Pancreas
D
12

From Assignment and compound assignment operators [expr.ass]

The meaning of x={v}, where T is the scalar type of the expression x, is that of x=T(v) except that no narrowing conversion (8.5.4) is allowed.

and from List-initialization [dcl.ini.list]

If a narrowing conversion (see below) is required to convert any of the arguments, the program is ill-formed.

So basically you can't ignore it, your program is ill-formed in presence of narrowing conversions.

From Implementation compliance:

Implementations are required to diagnose programs that use such extensions that are ill-formed according to this International Standard. Having done so, however, they can compile and execute such programs.

Bjarne Stroustroup say this:

Preventing narrowing

The problem: C and C++ implicitly truncates:

   int x = 7.3;        // Ouch!
    void f(int);
    f(7.3);         // Ouch!

However, in C++0x, {} initialization doesn't narrow:

int x0 {7.3};   // error: narrowing
int x1 = {7.3}; // error: narrowing
double d = 7;
int x2{d};      // error: narrowing (double to int)
char x3{7};     // ok: even though 7 is an int, this is not narrowing
vector<int> vi = { 1, 2.3, 4, 5.6 };    // error: double to int narrowing

The way C++0x avoids a lot of incompatibilities is by relying on the actual values of initializers (such as 7 in the example above) when it can (and not just type) when deciding what is a narrowing conversion. If a value can be represented exactly as the target type, the conversion is not narrowing.

char c1{7};      // OK: 7 is an int, but it fits in a char
char c2{77777};  // error: narrowing 

Note that floating-point to integer conversions are always considered narrowing -- even 7.0 to 7.

So in a way, narrowing also increases type safety.

Davie answered 20/12, 2011 at 17:18 Comment(1)
Excellent, detailed answer. Thanks very much.Pancreas

© 2022 - 2024 — McMap. All rights reserved.