const auto* versus const auto for Pointer Types
When working with references, C++ developers have been trained to use auto&, const auto&, or auto&& to avoid copies being made. However, when dealing with pointers, developers often do not use auto* but simply use auto instead. With pointers, there is no danger that you make accidental copies of the data, but there are other issues with omitting the *. Also, when working with pointers, there is a big difference between using const auto versus const auto*.
Let’s assume you have the following simple classes:
#include <memory> class Data {}; class Foo { public: Foo() : m_data(std::make_unique<Data>()) { } Data* GetData() { return m_data.get(); } private: std::unique_ptr<Data> m_data; };
The GetData() method simply returns a pointer to a Data instance.
When using auto, a lot of developers simply write the following:
Foo foo; auto d1 = foo.GetData();
The resulting type of d1 is Data*.
I actually recommend to write the following instead:
auto* d2 = foo.GetData();
d2 is also of type Data*, but the benefit is that you immediately see that you are dealing with a pointer. I know, in most IDE’s you can simply hover your mouse over the variable name and it will tell you the exact type. However, sometimes you are not working in an IDE. One such example is when doing code review in an external tool. Most of these tools do not show you that information when hovering over the name of a variable. This makes it a bit more difficult during code review to know that d2 is actually a pointer. When you write auto*, then it’s immediately obvious.
Now, let’s throw const into the mix. Again, most developers will not write the * with auto, so they write the following:
const auto d3 = foo.GetData();
However, this is most of the time not doing what you expect it to do!
Often, when you use const, you want to protect the thing to which the pointer is pointing to. A lot of developers assume that d3 is of type const Data*, but in fact, the type is Data* const, so it’s a const pointer to a non-const Data! Putting the const after the auto as follows doesn’t help, the type is still Data* const:
auto const d4 = foo.GetData();
When you use auto* in combination with const, then it’s behaving as you would expect. For example:
const auto* d5 = foo.GetData();
With this line, d5 is of type const Data* 🙂
If you really want a const pointer instead of const data, you put the const at the end:
auto* const d6 = foo.GetData();
d6 has type Data* const.
And finally, with this syntax you can make both the pointer and the data constant:
const auto* const d7 = foo.GetData();
d7 is of type const Data* const. You cannot achieve this if you omit the *.
All this is something to keep in mind. I’ve seen developers make mistakes against this several times.