Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If I use C-Style casts in my C++ project, is it worth refactoring to C++ casts?

I use C-style casts in my 15K LOC C++ project, 90% of the times for casts between child and base classes.

Even when I read that it is bad to use them, and that they can result in severe errors, as they are not type safe as the C++ casts, I still feel perfectly fine and comfortable with using them.

I have not experienced a single bug in my project so far that was caused by, for example, an accidentally mistyped C-Style cast - really.

There are two main reasons I have not been using them:

  • I didn't know enough about them yet
  • I didn't like their syntax, they are more verbose and harder to read for me

My questions:

  • (Why) Should I refactor my project to use C++-style casts?
  • Why should I use C++-style casts for my future projects?

I use as good as all other advantages C++ offers me, from OOP including virtual and abstract base classes, namespaces, the STL, and so on, just not the new type casting syntax. The argument "Why aren't you just using C then?" doesn't work for me.

like image 962
Ymir Avatar asked Feb 18 '11 21:02

Ymir


People also ask

Why is Static_cast better than C-style cast?

static_cast<>() gives you a compile time checking ability, C-Style cast doesn't. static_cast<>() is more readable and can be spotted easily anywhere inside a C++ source code, C_Style cast is'nt. Intentions are conveyed much better using C++ casts.

What is C-style cast?

C-style casts can be used to convert any type into any other type, potentially with unsafe results (such as casting an integer into a pointer type). (<type>)<value> This example casts an int to a double for the purpose of avoiding truncation due to integer division: double result = (double)4/5; Popular pages.

Does C have static cast?

Static casts are only available in C++. Static casts can be used to convert one type into another, but should not be used for to cast away const-ness or to cast between non-pointer and pointer types.


1 Answers

The main advantage of the C++-style casts is, as you've mentioned, the type safety. Each cast in C++ handles one specific sort of conversion (or a family of related conversions) and so the compiler can go and check that you're not accidentally doing more conversions that you intended, or a sequence of conversions that fundamentally isn't safe.

One thing to think about is that while it's great that you feel comfortable using C-style casts, and while it's great that you haven't made any mistakes with them, other people working on the code base might not be as facile with these casts as you are. Using the casting operators makes the code more self-documenting. If you have a C-style cast somewhere, someone else reading the code might not be able to immediately infer what it is that you're doing. If they see something like

T* ptr = (T*) var; 

They might not immediately be able to tell if this is

  1. A cast from a base class to a derived class or the other way around.
  2. A cast to strip constness off of var
  3. A cast from an integral type to a pointer.

While they can probably glean this from context, it's a lot more obvious what's going on if you use a cast like

T* ptr = static_cast<T*>(var); 

or

T* ptr = const_cast<T*>(var); 

Another reason to prefer the C++-style casting operators is that they make the code more resilient to change. For example, suppose I have this function:

void DoSomething(Base* ptr) {     Derived* derived = (Derived *) ptr;     DoSomethingElse(derived); } 

Now, suppose that I realize that this function isn't supposed to make any changes to its argument, so I decide to mark it const. For example:

void DoSomething(const Base* ptr) {     Derived* derived = (Derived *) ptr;     DoSomethingElse(derived); } 

But now we have a problem - my C-style cast which used to just do a downcast now also strips off constness. This can lead to an easy bug where DoSomethingElse mutates the pointer I pass in, even though the DoSomething method itself promises not to do this. If instead I wrote this code as

void DoSomething(Base* ptr) {     Derived* derived = static_cast<Derived *>(ptr);     DoSomethingElse(derived); } 

And then change the code by adding const:

void DoSomething(const Base* ptr) {     Derived* derived = static_cast<Derived *>(ptr);     DoSomethingElse(derived); } 

Now I'll get a compiler error telling me that my old cast is broken, which can lead me to discover that there is a logical error in the code (namely, that DoSomethingElse mutates its argument, so I can't naively make ptr a pointer-to-const.

So in short, using the C++ casting operators makes the code more readable and more maintainable. It makes the logic behind the code more explicit. And it makes the code less bug-prone by having the compiler catch errors either as you're making them or later on as you go back and change old code. I would recommend trying to use C++-style casting operators in the future for these main reasons.

As for whether you should go back and try to replace your current C-style casts with C++-style casts, that's really up to you. As an exercise, I'd suggest doing it just to practice learning what sorts of casts you're using. Plus, you might find a logic error in there, which would make the search worth your while!

like image 152
templatetypedef Avatar answered Sep 30 '22 07:09

templatetypedef