tags:

views:

11803

answers:

9

I've heard that, in C++, the static_cast function should be preferred to C-style or simple function-style casting. Is this true? Why?

+9  A: 

Objection your honour, asked and answered.

Graeme Perrow
I disagree, this other question was about describing the differences between casts introduces in C++. This question is about the real usefulness of static_cast, which is slightly different.
Vincent Robert
We could certainly merge the two questions, but what we'd need to preserve from this thread is the advantage of using functions over C-style casting, which is currently only mentioned in a one-line answer in the other thread, with no votes.
Tommy Herbert
Up voting because that link still provides useful information.
Pete
+1  A: 

static_cast, aside from manipulating pointers to classes, can also be used to perform conversions explicitly defined in classes, as well as to perform standard conversions between fundamental types:

double d = 3.14159265;
int    i = static_cast<int>(d);
Prakash
+5  A: 

static_cast means that you can't accidentally const_cast or reinterpret_cast, which is a good thing.

DrPizza
Additional (though rather minor) advantages over the C style cast is that it stands out more (doing something potentially bad should look ugly) and it's more grep-able.
Michael Burr
grep-ability is always a plus, in my book.
Branan
+5  A: 

It's about how much type-safety you want to impose.

When you write (bar) foo (which is equivalent to reinterpret_cast<bar> foo if you haven't provided a type conversion operator) you are telling the compiler to ignore type safety, and just do as it's told.

When you write static_cast<bar> foo you are asking the compiler to at least check that the type conversion makes sense and, for integral types, to insert some conversion code.

dysfunctor
(bar)foo is not equivalent to reinterpret_cast<bar>(foo). The rules for "(TYPE) expr" are that it will choose the appropriate C++ style cast to use, which may include reinterpret_cast.
Richard Corden
Good point. Euro Micelli gave the definitive answer for this question.
dysfunctor
+4  A: 

One pragmatic tip: you can search easily for the static_cast keyword in your source code if you plan to tidy up the project.

+53  A: 

The main reason is that classic C casts make no distinction between what we call static_cast<>() and reinterpret_cast<>(). Those two things are completely different things.

A static_cast<>() is usually safe. There is a valid conversion in the language, or an appropriate constructor that makes it possible. The only time is a bit risky is to cast down to an inherited class; you must make sure that the object is a actually the descendant that you claim it is, by means external to the language (like a flag in the object).

A reinterpret_cast<>() on the other hand is always dangerous. You tell the compiler: "trust me: I know this doesn't look like a foo, but it is".

The first problem is that it's almost impossible to tell which one will occur in a C-style cast without looking at large and disperse pieces of code and knowing all the rules.

Let's assume these:

class CMyClass : public CMyBase {...};
class CMyOtherStuff {...} ;

CMyBase  *pSomething; // filled somewhere

Now, these two are compiled the same way:

CMyClass *pMyObject;
pMyObject = static_cast<CMyClass*>(pSomething); // Safe; as long as we checked

pMyObject = (CMyClass*)(pSomething); // Same as static_cast<>
                                     // Safe; as long as we checked
                                     // but harder to read

However, let's see this almost identical code:

CMyOtherStuff *pOther;
pOther = static_cast<CMyOtherStuff*>(pSomething); // Compiler error: Can't convert

pOther = (CMyOtherStuff*)(pSomething);            // No compiler error.
                                                  // Same as reiterpret_cast<>
                                                  // and it's wrong!!!

As you can see, there is no easy way to distinguish between the two situations without knowing a lot about all the classes involved.

The second problem is that the C-style casts are too hard to locate. In complex expressions it can be very hard to see a C-style casts. It is virtually impossible to write an automated tool that needs to locate C-style casts (for example a search tool) without a full blown C++ compiler front-end. On the other hand, it's easy to search for "static_cast<" or "reinterpret_cast<".

pOther = reinterpret_cast<CMyOtherStuff*>(pSomething);
      // No compiler error.
      // but the presence of a reinterpret_cast<> is 
      // like a Siren with Red Flashing Lights in your code.
      // The mere typing of it should cause you to feel VERY uncomfortable.

That means that, not only are C-style casts more dangerous, but it's a lot harder to find them all to make sure that they are correct.

Euro Micelli
You shouldn't use `static_cast` for casting down an inheritance hierarchy, but rather `dynamic_cast`. That will return either the null pointer or a valid pointer.
David Thornley
@David Thornley: I agree, usually. I think I indicated the caveats to using `static_cast` in that situation. `dynamic_cast` might be safer, but it's not always the best option. Sometimes you do *know* that a pointer points to a given subtype, by means opaque to the compiler, and a `static_cast` is faster. In at least some environments, `dynamic_cast` requires optional compiler support and runtime cost (enabling RTTI), and you might not want to enable it just for a couple of checks you can do yourself. C++'s RTTI is only one possible solution to the problem.
Euro Micelli
+2  A: 

The question is bigger than just using wither static_cast or C style casting because there are different things that happen when using C style casts. The C++ casting operators are intended to make these operations more explicit.

On the surface static_cast and C style casts appear to the same thing, for example when casting one value to another:

int i;
double d = (double)i;                  //C-style cast
double d2 = static_cast<double>( i );  //C++ cast

Both of these cast the integer value to a double. However when working with pointers things get more complicated. some examples:

class A {};
class B : public A {};

A* a = new B;
B* b = (B*)a;                                  //(1) what is this supposed to do?

char* c = (char*)new int( 5 );                 //(2) that weird?
char* c1 = static_cast<char*>( new int( 5 ) ); //(3) compile time error

In this example (1) maybe OK because the object pointed to by A is really an instance of B. But what if you don't know at that point in code what a actually points to? (2) maybe perfectly legal(you only want to look at one byte of the integer), but it could also be a mistake in which case an error would be nice, like (3). The C++ casting operators are intended to expose these issues in the code by providing compile-time or run-time errors when possible.

So, for strict "value casting" you can use static_cast. If you want run-time polymorphic casting of pointers use dynamic_cast. If you really want to forget about types, you can use reintrepret_cast. And to just throw const out the window there is const_cast.

They just make the code more explicit so that it looks like you know what you were doing.

Dusty Campbell
+1  A: 

C Style casts are easy to miss in a block of code. C++ style casts are not only better practice; they offer a much greater degree of flexibility.

reinterpret_cast allows integral to pointer type conversions, however can be unsafe if misused.

static_cast offers good conversion for numeric types e.g. from as enums to ints or ints to floats or any data types you are confident of type. It does not perform any run time checks.

dynamic_cast on the other hand will perform these checks flagging any ambiguous assignments or conversions. It only works on pointers and references and incurs an overhead.

There are a couple of others but these are the main ones you will come across.

Konrad
A: 
  1. Allows casts to be found easily in your code using grep or similar tools.
  2. Makes it explicit what kind of cast you are doing, and engaging the compiler's help in enforcing it. If you only want to cast away const-ness, then you can use const_cast, which will not allow you to do other types of conversions.
  3. Casts are inherently ugly -- you as a programmer are overruling how the compiler would ordinarily treat your code. You are saying to the compiler, "I know better than you." That being the case, it makes sense that performing a cast should be a moderately painful thing to do, and that they should stick out in your code, since they are a likely source of problems.

See Effective C++ Introduction

JohnMcG