Dienstag, 25. Juni 2013

[C++11] Performance of casting and pointer

I played around with C++ trying to decrease build time by using pimpl and a base class.
Having some arbitrary base class in the pointer I need to cast it to the real data type when I wanna use it.
For the pointer I tried *, shared_ptr and unique_ptr and took times with and without casting.

The code is very basic:

For my test I compiled it without optimization and with debugging enabled.
Optimization is awesome. Still when I work on  a project most times I make debug builds because they are easier to debug. And when I can save time when debugging - then why not ;-)

Now the results (average of 8 tests):

Sample_Data*                                   ~5.8s
BaseClass* static_cast<>                       ~5.6s
BaseClass* dynamic_cast<>                      ~6.3s
shared_ptr<Sample_Data*>                       ~6.0s
unique_ptr<Sample_Data*>                       ~6.4s
shared_ptr<BaseClass> static_pointer_cast<>    ~9.0s
shared_ptr<BaseClass> dynamic_pointer_cast<>   ~9.5s
shared_ptr<BaseClass> static_cast<ptr.get()>   ~5.8s
shared_ptr<BaseClass> dynamic_cast<ptr.get()>  ~6.5s

This values look a bit strange to me.
Using normal pointers is faster then smart pointers is kind of understandable because there is less to do and manage. Same goes for static versus dynamic cast. 
But how can a static_cast from a normal pointer from a base class be faster then accessing the right class with a normal pointer directly?

What "normal" things can be seen?
→ A shared_ptr behaves as nearly as fast as a normal pointer.
→ A unique_ptr is slower then a shared_ptr.
→ A dynamic_(pointer_)cast is slower then a static_(pointer_)cast.
→ Casting shared_ptr is much slower then casting normal pointer.

So if you need to cast a lot - try to avoid smart pointers. Or cast the pointer that is inside the shared_ptr ( like this: static_cast<Derived_Class*>(baseClassSharedPointer.get()) ); But don't give that "free" pointer away!

When you know that the cast will work 100% of the time - prefer static cast.
If not 100% but most of the time then have a look at typeid.

Also: try to use smart pointers. Shared_ptr isn't that much slower then a normal pointer but you get some nice little extra: automatic destruction, and therefore maybe a bit less memory leaks ;-).