Skip to content
Tags

auto considered awesome

August 20, 2014

My last post about why you might not want to use auto may have left some people thinking that I think you shouldn’t use it. In fact I think you should almost always use it, as suggested in http://herbsutter.com/2013/08/12/gotw-94-solution-aaa-style-almost-always-auto/ However, like everything in C++, you should know what you are doing, because if you don’t, when you shoot yourself in the foot, you will probably blow your whole leg off.

You should read the above article, because it is a comprehensive discussion of why you might or might not want to use auto, and why you should use it all the time. Here I will add some points to the discussion about using it so that you don’t get yourself into trouble.

So now, I will go through every point in my last post, and then some.

const iterators

You should always use cbegin and cend when you are accessing a container in a way that will not change the container, period. By using the right functions you are documenting your code, and protecting yourself from accidentally changing the container. On top of that, there might be some optimisation that the compiler can make because everything is constant.

What size type do you want

Well there is no problem here if you know the standard, and use type suffixes appropriately. If you want an unsigned integer than you should write 10u. But then if you want specific size types you should probably construct them using the appropriate type. For example you could write

auto x = uint64_t{10} ;
auto y = int32_t{15} ;

and then x and y would be the right size.

What are my types?

Who cares what the types are? You should be coding to interfaces rather than exact types. Then, as long as what you write satisfies the appropriate interface, it doesn’t actually matter what type it is.

What is my return type

Again, if you must use this feature, you have to be careful and know how things work so that you return the right type of object. Then, if you need to copy and paste big expressions, then again, be careful. This problem is mitigated with C++14, since you don’t have to specify a return type at all if it can be deduced from the body of the function.

To reference, or not to reference?

Well that’s easy. It’s just like declaring any other variable. You don’t get a reference unless you ask for it. But again, you have to know the rules.

Other thoughts

Of course sometimes you need to write types down. Sometimes you actually need to allocate objects of a known type on the heap. But then, you should probably be using a smart pointer, and in that case you can still only write the type once, with the following

auto p = std::make_shared<T>(init, ...);

where T is the type you want, and init, ... is the arguments used to initialise the object. This way, you don’t even have to write new. In general, the idea here is that even when you do want to specify types, you only need to write the type down once, not several times as is common in older code.

In conclusion, there really seems to be no reason why you shouldn’t almost always use auto.

About these ads

From → Language

11 Comments
  1. I do not believe that any optimisation can be done by having a value const. Either the compiler has the visibility that the value doesn’t change regardless of constness, or it doesn’t and can’t assume anything because of const_cast.
    Constness is good for correctness, but I don’t think it can be used as an optimisation.

    • You know I think that you’re right. It’s one of those things that I read somewhere once, and I thought that it sounded reasonable. So then I never question it and I say the same thing myself. But after looking around it looks like there really isn’t any optimisation that can be done just because something is const.

      That doesn’t stop us using it for correctness though.

    • Modifying a const object is undefined behaviour, so the compiler can assume a const object will never be changed, whether through const_cast or by any other means, regardless of visibility.

      • Sure, but if you have a const reference to an object, that doesn’t mean that the object is const. It just means that you can’t change it through that reference, except that you can with const_cast. Usually, you are dealing with const references, for example through const iterators, so usually, the object could be changed somewhere else. So in practice, constness does not help with anything but documenting your code and helping you write correct code.

      • @Mat Modifying a const object is only undefined behavior if you const_cast away the constness of an object that was originally declared const.

  2. In my post in response to AAA style (http://josephmansfield.uk/articles/dont-use-auto-unless-you-mean-it.html), I was opposed to a fair few of the arguments for it.

    The big one that really bothers me is what you say under “What are my types?” Coding to interfaces does not mean completely discarding all type information. Coding to interfaces means expressing your types with the minimum number of requirements necessary. Unfortunately, we have to wait for concepts to be able to express requirements on types, so whether you choose AAA or ANA (almost never auto), it’s a very temporary choice.

    Still, I find it hard to stomach the argument that AAA doesn’t make code harder to read and understand. Of course it does – you’re providing absolutely no information about the object and forcing the reader to figure out what the initialiser does instead. This bad habit also often forces the programmer to put useful type information in the names of variables – oh dear!

    As I said, either approach will become obsolete in a few years, I just fear that pushing AAA will give people bad habits when concepts roll around.

    • It’s an interesting problem with no clear solution. For example, if you use gtkmm, then you probably want to avoid writing Glib::ref everywhere—there is really no need and it just clutters up your code. However, at the same time, I can easily imagine that you could have a function that only has auto for every return type, and you quickly get lost because you forget what all the types are supposed to be. I hate variables that have type information in them, it drives me crazy, lpsz this and hwnd that, argghh!! There is probably some careful balance between reducing clutter and getting lost.

      I am also not keen on the argument that modern IDEs help solve this problem by telling you what types are. As far as I know, the parsing ability of modern IDEs is not brilliant, so they don’t always help. But furthermore, I don’t even use an IDE, or rather, my IDE is vim and a terminal. I’m sure there are plenty of people who are the same. After using vim, I cannot for the life of me go back to using the mouse and arrow keys to navigate, so I will never have the option of hovering over a variable or typing . or -> and getting a list of types. Also in my experience, when you do that through a smart pointer, every IDE I have used has no idea at all.

      Yes, I definitely agree that concepts would solve some of these problems. Unfortunately they aren’t here yet.

  3. You probably meant “make_shared” at the end not “make_shared_ptr”.
    Cheers!

  4. I strongly disagree with “What are my types” and “what is my return type”, it’s better to have a typedef alias rather than “guessing” what the type is. I wonder how can you write the code (or even better – read the code) with all the “autos”

    • I disagree, especially for very generic code. When I wrote the variant class, there was zero point in knowing what the types were in a lot of the code, especially the “get” functions. I see great value in just deferring the type to “whatever that guy returns”.

      I also had great difficulty once programming with boost::spirit. For whatever I was doing, the type returned by something was completely irrelevant to what I needed. But, I had to go and find the right typedef somewhere, which was a nightmare, because at the time there was no auto.

      I think that in cases like that, auto makes for much cleaner and less error-prone code, because often the type really doesn’t matter, since for the most part you are deferring whatever happens to some other function. Duplicating the types just means that more can go wrong, and that there is more to change when you change something.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: