Auto* vs auto when using dynamic_cast<> in juce repo


#1

I noticed this usage in a lot of the juce code on github and asked about it over in ##c+±general. The discrepancy between auto* and auto:
if( auto* exporterItem = dynamic_cast<ConfigTreeItemTypes::ExporterItem*> )
vs
if (auto program = dynamic_cast<BitmapLEDProgram*> (grid->getProgram()))

there is a channel bot named geordi that you can write code snippets to. one of the users in the channel responded to my query about this topic with this:

{ int i{3}; int* ptr{&i}; auto a = ptr; cout << TYPE(a); }

geordi’s output: lvalue int*

i tested using auto* a instead:

{ int i{3}; int* ptr{&i}; auto* a = ptr; cout << TYPE(a); }

geordi’s output was the same. lvalue int*

So, if auto* a = dynamic_cast<> and auto a = dynamic_cast<> are basically the same thing, doesn’t it make sense to just use auto a and omit the *? Or commit to always using auto* whenever you’re using dynamic_cast<> to remind yourself you’re getting a pointer back?

Seems like the stylistic choice of using auto* defeats the purpose of the auto keyword…


#2

In an ideal world, you would always just use auto. However, due to some pre-C++11 smart pointer oddities you can end up in very hot water using auto when you’re expecting a raw pointer.

For example, if you use auto to reference a juce::ScopedPointer, auto will be deduced to a juce::ScopedPointer and you’ll steal the managed object and it will be deleted when the auto goes out of scope.

The other tricky situation is with juce::ReferenceCountedObject where auto will deduce to a juce::ReferenceCountedObject, you’ll bump the reference count and then there’s a chance if you’re checking the use count it will be one more than you expect.

Having spent literally days tracking down and fixing bugs like this after a slew of explicit types being changed to autos, I now have a rule to use auto* when I know I’m expecting a raw pointer. This makes the above mentioned bugs impossible as you’ll get compiler errors.


However, you can argue several things, firstly that in your specific example, the scope is narrow and you are already explicitly stating the type in the dynamic cast so yes, auto* is probably overkill here.

Secondly, if you only use full C++11 smart pointers (std::unique_ptr, std::shared_ptr etc.) it will also be impossible to get in to the same hot water as above.

One argument for the use of auto in these situations is that the type could change to a non-pointer-like type and code should magically just work. Of course, that isn’t the case yet* as you have to use different operators to make calls on the object (-> vs .) so if you’re going to have to change the code to call a reference for example, you might as well change the auto* at the same time.

(* I say yet as the operator.() C++ proposal may change this in the future).