C++ Casts

Once you explain something enough, it’s worth writing it down, simply so you can link it. :)

There are five cast operators in C++:

cppreference.com does a great job documenting the semantics of the various cast operators, so I won’t cover them here. Instead, let’s define some rules that will keep you and your teammates sane and prevent a class of bug-causing accidents.

Enable Warnings For Implicit Conversions

Enable your compiler’s warnings for implicit conversions of float -> int, int -> float, int -> char, and so on. On the hopefully-rare occasion you actually want said conversion, use a static_cast.

Avoid Casts

When possible, avoid casts entirely. If you find yourself wanting dynamic_cast, consider whether a virtual function will suffice. Virtual functions are cheaper and your design becomes more flexible. Instead of:

if (auto p = dynamic_cast<Console*>(output)) {
    p->setColor(RED);
} else {
    p->output("FAIL: ");
}

Try:

p->onFailure();

Also, consider restructuring your code so type knowledge is explicit. Sometimes, instead of a single list of base class pointers, it works out better to store a list per subtype. That is, instead of std::vector<Material*> materials;, the following design might work a little more smoothly in practice: std::vector<StaticMaterial*> staticMaterials; std::vector<DynamicMaterial*> dynamicMaterials;

If you’re converting between floats and ints all the time, see if you can stick with one or the other. Some platforms severely penalize said conversions.

In general, frequent use of cast operators indicates the software’s design can be improved.

Use Weaker Casts

Use the most restrictive cast operator for the situation. Casts should be precise, specific, and should fail if the code is changed in a way that makes the conversion meaningless.

Prefer static_cast over reinterpret_cast

static_cast will give a compile-time error if attempting to convert C* to D* where neither C nor D derive from each other. reinterpret_cast and C-style casts would both allow said conversion.

Prefer reinterpret_cast over C-style Casts

reinterpret_cast does not allow casting away constness. You must use const_cast for that. C-style casts, again, let you do anything. Prefer the weaker cast operation.

Avoid const_cast

I’m not sure I’ve ever seen a justified use of const_cast. It’s almost always some kind of clever hack. Just get your constness right in the first place.

Avoid C-style Casts

I’m going to repeat myself. Don’t use C-style casts. They let anything by. When you refactor something and you find yourself debugging some insane issue that should have been a compiler error, you’ll wish you used a weaker cast operator.

Don’t Cast Function Pointers to void*

It’s undefined behavior.

2 thoughts on “C++ Casts”

  1. The one case I have seen where a const_cast is the cleanest way to do something is when using JNI and Java ByteBuffers. You must mark the ByteBuffer as read-only from native to actually make the const-ness real, though.

    Where does dynamic_cast sit as far as strictness?

  2. dynamic_cast is fine, as long as you know you really need it. :) In general, your software designs ought to avoid querying the type of an object, however, as it makes your design more brittle.

Leave a Reply

Your email address will not be published. Required fields are marked *