tags:

views:

307

answers:

6

My knowledge of C++ at this point is more academic than anything else. In all my reading thus far, the use of explicit conversion with named casts (const_cast, static_cast, reinterpret_cast, dynamic_cast) has come with a big warning label (and it's easy to see why) that implies that explicit conversion is symptomatic of bad design and should only be used as a last resort in desperate circumstances. So, I have to ask:

Is explicit conversion with named casts really just jury rigging code or is there a more graceful and positive application to this feature? Is there a good example of the latter?

+14  A: 

There're cases when you just can't go without it. Like this one. The problem there is that you have multiple inheritance and need to convert this pointer to void* while ensuring that the pointer that goes into void* will still point to the right subobject of the current object. Using an explicit cast is the only way to achieve that.

There's an opinion that if you can't go without a cast you have bad design. I can't agree with this completely - different situations are possible, including one mentioned above, but perhaps if you need to use explicit casts too often you really have bad design.

sharptooth
I agree with sharptooth's final comment here, just because you have an explicit cast does not mean you have bad code, but if you are casting back and forward every other line then you need to rethink things. Casting is a valid operation but it is something that should not be over used.
Martin York
Certainly never used to cast away compile warnings and errors!
Alan
+7  A: 

There are situations when you can't really avoid explicit casts. Especially when interacting with C libraries or badly designed C++ libraries (like the COM library sharptooth used as examples).

In general, the use of explicit casts IS a red herring. It does not necessarily means bad code, but it does attract attention to a potential dangerous use.

However you should not throw the 4 casts in the same bag: static_cast and dynamic_cast are frequently used for up-casting (from Base to Derived) or for nagivating between related types. Their occurrence in the code is pretty normal (indeed it's difficult to write a Visitor Pattern without either).

On the other hand, the use of const_cast and reinterpret_cast is much more dangerous.

  • using const_cast to try and modify a read-only object is undefined behavior (thanks to James McNellis for correction)
  • reinterpret_cast is normally only used to deal with raw memory (allocators)

They have their use, of course, but should not be encountered in normal code. For dealing with external or C APIs they might be necessary though.

At least that's my opinion.

Matthieu M.
Technically it's only _modifying_ a read-only object through the result of a `const_cast` that results in undefined behavior. The `const_cast` itself is "safe."
James McNellis
Thanks, I tweaked the sentence accordingly. Effectively any cast is safe in itself, it's only using the result that may invoke undefined behavior.
Matthieu M.
COM is not a C++ library and was therefore not designed with good C++ semantics in mind. This does not make it bad -- it merely defines it's own object model. (COM is a PITA for *other* reasons though)
Billy ONeal
I don't mean to demean COM, but as a developer I always struggle to design interfaces that are easy to use right and hard to use wrong. I find it a pity that they did not refine the C++ interface better.
Matthieu M.
+2  A: 

IMO, like most things, they're tools, with appropriate uses and inappropriate ones. Casting is probably an area where the tools frequently get used inappropriately, for example, to cast between an int and pointer type with a reinterpret_cast (which can break on platforms where the two are different sizes), or to const_cast away constness purely as a hack, and so on.

If you know what they're for and the intended uses, there's absolutely nothing wrong with using them for what they were designed for.

AshleysBrain
+3  A: 

How bad a cast is typically depends on the type of cast. There are legitimate uses for all of these casts, but some smell worse than others.

const_cast is used to cast away constness (since adding it doesn't require a cast). Ideally, that should never be used. It makes it easy to invoke undefined behavior (trying to change an object originally designated const), and in any case breaks the const-correctness of the program. It is sometimes necessary when interfacing with APIs that are not themselves const-correct, which may for example ask for a char * when they're going to treat it as const char *, but since you shouldn't write APIs that way it's a sign that you're using a really old API or somebody screwed up.

reinterpret_cast is always going to be platform-dependent, and is therefore at best questionable in portable code. Moreover, unless you're doing low-level operations on the physical structure of objects, it doesn't preserve meaning. In C and C++, a type is supposed to be meaningful. An int is a number that means something; an int that is basically the concatenation of chars doesn't really mean anything.

dynamic_cast is normally used for downcasting; e.g. from Base * to Derived *, with the proviso that either it works or it returns 0. This subverts OO in much the same way as a switch statement on a type tag does: it moves the code that defines what a class is away from the class definition. This couples the class definitions with other code and increases the potential maintenance load.

static_cast is used for data conversions that are known to be generally correct, such as conversions to and from void *, known safe pointer casts within the class hierarchy, that sort of thing. About the worst you can say for it is that it subverts the type system to some extent. It's likely to be needed when interfacing with C libraries, or the C part of the standard library, as void * is often used in C functions.

In general, well-designed and well-written C++ code will avoid the use cases above, in some cases because the only use of the cast is to do potentially dangerous things, and in other cases because such code tends to avoid the need for such conversions. The C++ type system is generally seen as a good thing to maintain, and casts subvert it.

David Thornley
A: 

There is an irony to explicit casts. The developer whose poor C++ design skills lead him to write code requiring a lot of casting is the same developer who doesn't use the explicit casting mechanisms appropriately, or at all, and litters his code with C-style casts.

On the other hand, the developer who understands their purpose, when to use them and when not to, and what the alternatives are, is not writing code that requires much casting!


Check out the more fine-grained variations on these casts, such as polymorphic_cast, in the boost conversions library, to give you an idea of just how careful C++ programmers are when it comes to casting.

John
A: 

Casts are a sign that you're trying to put a round peg in a square hole. Sometimes that's part of the job. But if you have some control over both the hole and the peg, it would be better not create this condition, and writing a cast should trigger you to ask yourself if there was something you could have done so this was a little smoother.

JohnMcG