I like the top answer in https://stackoverflow.com/questions/6855686/what-is-the-difference-between-static-cast-and-reinterpret-cast.
Both are unsafe casts and could hit run time errors, but RC is more unsafe. RC turns off compiler error checking, so you are on your own in the dark forest.
I feel RC is the last resort, when you have control on the bit representation of raw data , with documented assurance this bit representation won’t change.
In a real example — a raw byte array comes in as a char array, and you RC it into (pointer to) a packed struct. The compiler has no reason to believe the char array can be interpreted as that struct, so it skips all safety checks. If the raw data somehow changes you get a undefined behavior at run time. In this case SC is illegal — will not pass compiler.
http://stackoverflow.com/questions/17880960/what-does-it-mean-to-reinterpret-cast-a-pointer-as-long shows a real use case of reinterpret_cast from pointer to integer, and reinterpret_cast back to pointer.
What if I serialized an object to xml and the object contains a pointer field (reference field is less common but possible)? Boost::serialization would unwrap the pointer and serialize the pointee object.
explict MyType(int); // would disallow
MyType a = 77;
http://en.cppreference.com/w/cpp/language/converting_constructor has a solution:
MyType a = (MyType) 77; // Static cast would invoke the explicit conversion constructor!
Most custom types should make conversion constructors explicit to avoid hidden bugs, but smart pointer need an implicit conversion constructor, to support
SmartPtr<int> myPtr = new int(77);
–A real example from CFM quant code
FwdCurve::const_iterator iter = find( key ); //non-const itr
QL_ASSERT( iter != ((FwdCurve * const) this)->end(), "not found" ); // original code probably before "explicit".
// I had to change it to
FwdCurve_iterator endItr = ((FwdCurve * const) this)->end();
QL_ASSERT( iter != FwdCurve_const_iterator(endItr), "not found" ); //call the conversion ctor explicitly
See other posts about OOC and cvctor. I am now convinced by [[safeC++]] that it’s better to avoid both. Instead, Use AsXXX() method if converting from YYY to XXX is needed. Reason is type safety. In an assignment (including function input/output), it is slightly hacky if LHS is NOT a base type of RHS. Implicit conversion is like Subversion of compiler’s type enforcement — Given a function declared as f(XXX), it should ideally be illegal to pass in a YYY. However, The implicit converters break the clean rule, from the back door.
As explained concisely on P8 [[safeC++]], The OOC is provided specifically to support implicit conversion. In comparison, The cvctor is more likely to be a careless mistake if without “explicit”.
Favor explicit conversion rather than implicit conversion. Some manager in Millennium pointed out that c++ syntax has too many back doors and is too “implicit”. Reading a piece of code you don’t know what it does, unless you have lots of experience/knowledge about all the “back-doors”.
http://bigblog.tanbin.com/2010/01/new-and-dynamiccast-exceptions-quick.html shows that dynamic_cast of a pointer returns NULL upon failure. Why not throw exception?
A: for efficient test-down-cast. dynamic_cast is the only solution. If it throws exception, the test would have to incur the cost of try/catch.
See P59 [[beyond c++ standard lib]]
See also posts on the “same” topic.
Note many inefficient implicit conversions are selectively, optionally “optimized away” by various compiler options. This adds even more complexity.
# proxy classes (like in [[more effC++]]) rely heavily on implicit translations
# smart pointer are drop-in replacement for raw pointers, and always relies on implicit compiler translations.
# “–any literal string–” anywhere in source code is implicitly converted to a char*const
# unnamed temporary object creation by compiler. [[more eff c++]]
# [[c++ primer]] here are 3 identical func declarations because all array params are implicitly converted to ptr param. This is still very relevant because arrays are far more widely used than vectors (C is widespread) —
void f(int * )
void f(int )
void f(int )
#51 [[effC++]] Item 19 points out that if your Rational class overloads operator* with a Rational argument, then “aRational * 2” still works because compiler converts it first into
aRational.operator*(2); // then it needs to convert 2 to a Rational object, so it converts the call into
const Rational temp(2);
#50) if f() declares a param of type Animal, you can pass in a Shape variable, if there’s a converter. (See effC++ Item 26). Applies to any LHS=RHS expression like
** Type5 var2 = var3ofUnrelatedType // you get either a Type5 conversion ctor or a conversion method in UnrelatedType,
#10) overloading the arrow operator ie “->”. See P19/23 [[boost]]. IBM explains — The statement x->f() is interpreted as (x.operator->())->f()
Smart pointers are the infrastructure of infrastructures for a quant library.
Minor performance issues become performance critical in this foundation component. One example is the allocation of the reference count. Another example is the concurrent update of the reference count. But here my focus is yet another performance issue — the lowly pointer-cast. (I don’t remember why performance is a problem … but I believe it is.)
C++ support 4 specific casts but smart pointers need to -efficiently- implement const_cast and dynamic_cast, in addition to the implicit upcast.
Q1: why can’t I assign a smartPtr-of-int instance to a variable declared as smartPtr of Dog?
A: compiler remembers the type of each pointer variable.
Q2: in that case, should c++ compiler allow me to assign a SP-of-Derived instance to a variable declared as SP of Base?
%%A: I don’t think so. I don’t think every smart pointer automatically supports upcast, but boost shared_ptr does, by design. See below.
For Boost, a Barcap expert said there’s an implicit cast from shared_ptr of T (RHS) to (LHS) shared_ptr of const T. See the special casting methods in http://www.boost.org/doc/libs/1_48_0/libs/smart_ptr/shared_ptr.htm
Specifically, boost says shared_ptr can be implicitly converted to shared_ptr whenever T* can be implicitly converted to U*. This mimics the behavior of raw pointers. In particular, shared_ptr is implicitly convertible to shared_ptr (i.e. add constness), to shared_ptr where U is an public/protected base of T (i.e. upcast), and to shared_ptr.I believe this is the same “member template” magic in the smart pointer chapter of [[more effC++]]
Allow me to explain the basics — in basic C++, a raw-ptr-to-T instance can be assigned to these variables —
T const * my_ptr_to_const_T;
U * my_ptr_to_a_T_parent_class_U;
void * my_ptr_to_void;
Therefore a raw ptr supports these 3 (among others) casts implicitly. So does shared_ptr.