I happen to maintain the DB2 coding standards, which are mostly concerned with portability, and not style. I’ve joked that I was given that job since I had “broken the build” more than anybody else, so was most qualified to let others know how not to do so.
In our coding standards we have a prohibition against the use of exceptions. This is a historical restriction because we’ve built with compilation flags like -qnoeh (no exception handling) on some platforms to get a bit of additional performance. These days the compilers do much better at not degrading performance when exception handling is allowed and not used, but since our performance folks will sell their kids for a 1% improvement, we’ve kept using flags like this and the associated restriction. Components that must (or want) to use exception handling must “firewall” any exceptions, not letting them get thrown to external code (and also explicitly enable exceptions for their code).
We had a note in the coding standards not to use RTTI (Run Time Type Identification), because exceptions are required. That was a confusing and incomplete statement to include in our standards. It was interpreted by one developer as meaning that none of:
were allowed. However, only the dynamic_cast is a RTTI operation, and only the dynamic_cast will throw an exception when the cast doesn’t match the underlying type.
I’ve now fixed up our coding standards. It now references dynamic_cast instead of RTTI.
The DB2 code is still very C’ish, compiled with a C++ compiler. I’d say the bulk of the casts in our code are old style C casts, and that most of our developers (including myself) don’t even know when to use the “new” cast operations. Here’s some thoughts on these:
- I’ve seen a fair amount of const_cast use in our code, and I know personally how this can be very useful. An example:
volatile int x ;
void foo( int * y ) ;
foo( const_cast<short *>(&x) ) ; // compilation error
foo( const_cast<int *>(&x) ) ; // allowed. Just strips the volatile (or const) off the pointer type.
- A second nice use of const_cast<>() is to enforce type checking in macros. If the macro parameter is supposed to be a pointer to type T, you can enforce that by using a const_cast<T*>. This assumes that you don’t actually care about the const-ness of the pointer, and will force a compile error if the macro is used with any other type.
- In general I don’t think it’s a bad idea to use the new cast operators, since they represent a hierarchy of weaker than C style casts. You can also search for cast operations by name in a given file if they are used, which is much harder to do with a C style cast.
- I’m not sure how much use of static_cast<> and reinterpret_cast<> we have in the code.
Declaring my own stupidity, without looking them up, I didn’t personally know how to use the “new style” static_cast and reinterpret_cast operations correctly. I use a C cast by habit unless I’m trying to strip const or volatile attributes (or enforce a type in a macro).
If DB2 coders start using these, it will likely confuse old guys like me for a while, but I figure I can learn about these.
As a step in this direction, I see some helpful looking info in the C++ reference page on explicit_cast
My take on reference page is roughly: If there is a place to use a C cast, then you can use:
- const_cast if it compiles. If not you can use:
- static_cast. If that doesn’t compile you can use:
- reinterpret_cast. If that doesn’t compile you can use:
- (In code where exceptions are allowed:) dynamic_cast.
- If that doesn’t work or is not allowed you can use:
A C style cast.