74

I am new to C++ style casts and I am worried that using C++ style casts will ruin the performance of my application because I have a real-time-critical deadline in my interrupt-service-routine.

I heard that some casts will even throw exceptions!

I would like to use the C++ style casts because it would make my code more "robust". However, if there is any performance hit then I will probably not use C++ style casts and will instead spend more time testing the code that uses C-style casts.


Has anyone done any rigorous testing/profiling to compare the performance of C++ style casts to C style casts?

What were your results?

What conclusions did you draw?

Mysticial
  • 464,885
  • 45
  • 335
  • 332
Trevor Boyd Smith
  • 18,164
  • 32
  • 127
  • 177
  • I might have to add a bounty to this one... that is how interested I am. – Trevor Boyd Smith Mar 23 '09 at 19:51
  • You've already had two accurate (if I say so myself) answers. –  Mar 23 '09 at 20:04
  • The current answers here indicate that C++ style static_cast does not have a runtime performance hit. Would someone please comment or add some explanation as to why they would have the same performance? ( The question is purposefully vague. ) – Trevor Boyd Smith Mar 23 '09 at 20:15
  • Well, why don't you measure it yourself? It is trivially easy to do so. – Brian Neal Mar 23 '09 at 20:17
  • 1
    Why wouldn't they have the same performance? The only one that has any extra run-time cost is dynamic_cast, and you can't do that in C anyway. – Brian Neal Mar 23 '09 at 20:19
  • Because they do the same thing –  Mar 23 '09 at 20:21
  • 2
    Updated my answer. It now quotes chapter and verse from the standard. They do, as Neil said, do the same thing. – jalf Mar 23 '09 at 20:39
  • reinterpret and static casts do the same as C-style casts - difference being that static won't let you do 'unsafe' casts, whereas reinterpret disables safety. Grep'ing for C++-style casts = <3, compared to c-style :) – snemarch Mar 23 '09 at 21:13
  • @snemarch: Add to this statement "disables safety during the compile step". The produce identical code. static_cast just is picky about whether it will cause a compiler error or not. – jmucchiello Dec 23 '09 at 00:01
  • 1
    @jmucchiello: Old question, but I stumbled over it and want to make this clear for future readers: `static_cast` and `reinterpret_cast` will NOT always produce the same runtime code and there is actually very little overlap in what conversions are possible with both casts. E.g.: You can't use `reinterpret_cast` to cast from floating point to int (but ` from `double*` to `int*`) and when you use `static_cast` for this, it isn't free but will actually require the execution of one or more instructions (as would a c-style cast). In case of classes, `static_cast` might even invoke a function call – MikeMB Apr 22 '16 at 10:53

7 Answers7

102

If the C++ style cast can be conceptualy replaced by a C-style cast there will be no overhead. If it can't, as in the case of dynamic_cast, for which there is no C equivalent, you have to pay the cost one way or another.

As an example, the following code:

int x;
float f = 123.456;

x = (int) f;
x = static_cast<int>(f);

generates identical code for both casts with VC++ - code is:

00401041   fld         dword ptr [ebp-8]
00401044   call        __ftol (0040110c)
00401049   mov         dword ptr [ebp-4],eax

The only C++ cast that can throw is dynamic_cast when casting to a reference. To avoid this, cast to a pointer, which will return 0 if the cast fails.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 3
    A C++ style cast is never replaced by a C-style cast. If anything, it's the other way around. The standard only specifies the behavior of the C++-style casts. The C-style ones are described in terms of the C++ ones. – jalf Mar 23 '09 at 20:42
  • 1
    @jalf yes - I meant replaced conceptualy –  Mar 23 '09 at 20:44
  • 2
    Yeah, but might be worth making it 110% clear, if the OP is going to accept it. ;) – jalf Mar 23 '09 at 20:46
  • 21
    But the assembler listing... the ASSEMBLER LISTING!!! What does he want, *blood*? :) – Daniel Earwicker Mar 23 '09 at 20:54
  • 1
    Great answer, the conceptual comparison is accurate. – Matt Joiner Nov 15 '10 at 02:35
48

The only one with any extra cost at runtime is dynamic_cast, which has capabilities that cannot be reproduced directly with a C style cast anyway. So you have no problem.

The easiest way to reassure yourself of this is to instruct your compiler to generate assembler output, and examine the code it generates. For example, in any sanely implemented compiler, reinterpret_cast will disappear altogether, because it just means "go blindly ahead and pretend the data is of this type".

Daniel Earwicker
  • 114,894
  • 38
  • 205
  • 284
21

Why would there be a performance hit? They perform exactly the same functionality as C casts. The only difference is that they catch more errors at compile-time, and they're easier to search for in your source code.

static_cast<float>(3) is exactly equivalent to (float)3, and will generate exactly the same code.

Given a float f = 42.0f reinterpret_cast<int*>(&f) is exactly equivalent to (int*)&f, and will generate exactly the same code.

And so on. The only cast that differs is dynamic_cast, which, yes, can throw an exception. But that is because it does things that the C-style cast cannot do. So don't use dynamic_cast unless you need its functionality.

It is usually safe to assume that compiler writers are intelligent. Given two different expressions that have the same semantics according to the standard, it is usually safe to assume that they will be implemented identically in the compiler.

Oops: The second example should be reinterpret_cast, not dynamic_cast, of course. Fixed it now.

Ok, just to make it absolutely clear, here is what the C++ standard says:

§5.4.5:

The conversions performed by

  • a const_cast (5.2.11)
  • a static_cast (5.2.9)
  • a static_cast followed by a const_cast
  • a reinterpret_cast (5.2.10), or
  • a reinterpret_cast followed by a const_cast.

can be performed using the cast notation of explicit type conversion. The same semantic restrictions and behaviors apply. If a conversion can be interpreted in more than one of the ways listed above, the interpretation that appears first in the list is used, even if a cast resulting from that interpretation is ill-formed.

So if anything, since the C-style cast is implemented in terms of the C++ casts, C-style casts should be slower. (of course they aren't, because the compiler generates the same code in any case, but it's more plausible than the C++-style casts being slower.)

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
jalf
  • 243,077
  • 51
  • 345
  • 550
  • 1
    Given your comment of: "it is usually safe to assume that they will be implemented identically in the compiler". Do you or have you done any embedded work or real-time-critical work? – Trevor Boyd Smith Mar 23 '09 at 20:20
  • dynamic_cast will only throw when operating on references. If it is working on a pointer, it will return 0 if the cast fails. And why on earth would you use dynamic_cast on a float* to int* conversion? That makes no sense. – Brian Neal Mar 23 '09 at 20:23
  • oh oops, I meant reinterpret_cast, of course. It's fixed now. Thanks for pointing it out. :) – jalf Mar 23 '09 at 20:45
  • 3
    +1. haha 5.4.5 was the first that came to mind when i read that question :D – Johannes Schaub - litb Mar 23 '09 at 21:11
  • Oh jeez, don't tell me you could *remember* that it was 5.4.5... I had to look it up! ;) – jalf Mar 23 '09 at 23:22
  • haha, nono don't be afraid. i just knew C style casts are defined in terms of C++ style ones :p i got no love for remembering section numbers like that :) – Johannes Schaub - litb Mar 24 '09 at 00:33
  • @litb: by the way, I don't suppose you could cast some light on http://tinyurl.com/c9daz8 ? ;) – jalf Mar 24 '09 at 04:01
19

There are four C++ style casts:

  • const_cast
  • static_cast
  • reinterpret_cast
  • dynamic_cast

As already mentioned, the first three are compile-time operations. There is no run-time penalty for using them. They are messages to the compiler that data that has been declared one way needs to be accessed a different way. "I said this was an int*, but let me access it as if it were a char* pointing to sizeof(int) chars" or "I said this data was read-only, and now I need to pass it to a function that won't modify it, but doesn't take the parameter as a const reference."

Aside from data corruption by casting to the wrong type and trouncing over data (always a possibility with C-style casts) the most common run-time problem with these casts is data that actually is declared const may not be castable to non-const. Casting something declared const to non-const and then modifying it is undefined. Undefined means you're not even guaranteed to get a crash.

dynamic_cast is a run-time construct and has to have a run-time cost.

The value of these casts is that they specifically say what you're trying to cast from/to, stick out visually, and can be searched for with brain-dead tools. I would recommend using them over using C-style casts.

Max Lybbert
  • 19,717
  • 4
  • 46
  • 69
  • 3
    Actually, `static_cast` can also result in a runtime operation, just like c-style cast can (e.g. when you cast from floating point to integer and vice versa). – MikeMB Apr 22 '16 at 10:35
  • 1
    Why use `static_cast` to convert between floating point and integers? You can just assign: `double d = 5; int i = d;`. The conversion may include a runtime cost, but you have to pay that cost even if you don't write `static_cast`. – Max Lybbert Apr 22 '16 at 15:17
  • 1
    There are contexts, where implicit narrowing conversion is not allowed (e.g. list initialization) or where you want to make the conversion explicit. E.g. to select a certain overload or to document (to you or the compiler) that you are aware of the conversion going on. Also, the conversion float to int is just one example - think of explicit conversion operators/constructors of classes or up/down casting a pointer in a hierarchy, with multiple inheritance. – MikeMB Apr 22 '16 at 16:13
  • 1
    Yes, it is no additional overhead over c-style casts or implicit conversion. What I wanted spell out explicitly is that `static_cast` does more than just tell the compiler to interpret the bits differently (which is what `reinterpret_cast` and `const_cast` do). – MikeMB Apr 22 '16 at 16:13
4

When using dynamic_cast several checks are made during runtime to prevent you from doing something stupid (more at the GCC mailing list), the cost of one dynamic_cast depends on how many classes are affected, what classes are affected, etc.
If you're really sure the cast is safe, you can still use reinterpret_cast.

tstenner
  • 10,080
  • 10
  • 57
  • 92
  • If you find you need to use reinterpret_cast, you are definitely venturing into "implementation specific" territory, and possibly "undefined behaviour" land too –  Mar 23 '09 at 20:22
  • Please note that reinterpret_cast may be subject to different aliasing rules than static_cast etc. – leander Mar 23 '09 at 20:28
3

Although I agree with the statement "the only one with any extra cost at runtime is dynamic_cast", keep in mind there may be compiler-specific differences.

I've seen a few bugs filed against my current compiler where the code generation or optimization was slightly different depending on whether you use a C-style vs. C++-style static_cast cast.

So if you're worried, check the disassembly on hotspots. Otherwise just avoid dynamic casts when you don't need them. (If you turn off RTTI, you can't use dynamic_cast anyway.)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
leander
  • 8,527
  • 1
  • 30
  • 43
  • I'd be interested to see an example of the use of dynamic_cast when you don't need it. –  Mar 23 '09 at 20:38
  • 1
    An example could be if you downcast to a derived class (so you'd often use dynamic_cast), but you already know that the cast is legal, so you can use static_cast instead. – jalf Mar 23 '09 at 20:47
  • 1
    @Neil: I guess I meant more along the lines of "refactor to avoid dynamic_cast". I look pretty hard at the consequences before I start sticking "virtual" in inheritance hierarchies, because I *know* I'm making a tradeoff, and sometimes choosing a different design pattern can solve the problem... – leander Mar 24 '09 at 15:51
  • @Neil: if you're _sure_ it's a safe downcast and there's no virtual inheritance, you can use static_cast instead. Also, I believe you _can_ use dynamic_cast for upcasts, but that'd generally be silly (perhaps excepting virtual inheritance?). Treading into less-known territory here... – leander Mar 24 '09 at 15:55
  • "I've seen a few bugs filed against my current compiler where the code generation or optimization was slightly different depending on whether you use a c-style vs. c++-style static_cast cast.": I wonder if the C-style cast was doing more than one thing (const_cast *and* static_cast, f.e.). – Max Lybbert Mar 24 '09 at 19:17
2

The canonical truth is the assembly, so try both and see if you get different logic.

If you get the exact same assembly, there is no difference- there can't be. The only place you really need to stick with the old C casts is in pure C routines and libraries, where it makes no sense to introduce C++ dependence just for type casting.

One thing to be aware of is that casts happen all over the place in a decent sized piece of code. In my entire career I've never searched on "all casts" in a piece of logic- you tend to search for casts to a specific TYPE like 'A', and a search on "(A)" is usually just as efficient as something like "static_cast<A>". Use the newer casts for things like type validation and such, not because they make searches you'll never do anyway easier.

user3726672
  • 187
  • 2