Skip to content

auto considered harmful

August 6, 2014

So the auto keyword is wonderful isn’t it? Maybe, maybe not. Whilst it can reduce the clutter when dealing with long type names, especially with templates, it has a few disadvantages.

const iterators

Suppose that you have a non-const reference to a container that you wish to iterate through, and not change. You might do something like:

f(Container& c)
  auto iter = c.begin();
  while (iter != c.end())
    //do something here

This would be wrong, because what you want is a constant iterator into the container, since you are not changing it. There are two ways to fix it, by using a for each loop or cbegin and cend. With a for each loop you get a reference to the item.

for (const auto& v : c)
  //do something here

when you actually want the iterators, you can use auto iter = c.cbegin().

What size type do you want?

When you write any of the following

auto i = 10;
auto f = 4.5;

are you sure you want sizes for i and f that the compiler will give you? If you want i to be unsigned, and f to be a double, then you might not get what you want. Then your code might also break on another platform.

What are my types?

If you use auto too much, then you will come back to your code next week and not have a clue what you have written. If every object is declared with auto, then you have no idea what is going on, and it might be easy to make a mistake, or get lost in fixing your code. As much as auto can unclutter your code, type names are also documentation.

What is my return type?

It might seem nice to not have to declare the type of some convoluted long template expression, so you use auto and decltype for a trailing return type. But, you have copied and pasted your long expression, and if you change the return expression but not the type, such that they are still compatible, but not what you want, then you have a problem. You might want to return a copy, but you return a reference, for example, and your trailing return type hides that.

To reference, or not to reference?

When using auto, you have to consider whether you want a reference or not. Consider the following code

int x;
auto& y = x;
auto z = y;
auto& a = 5;

The first line declares an integer x, no problems there. The second line declares y to be a reference to x. Even though y is a reference type, the third line declares z to be a copy of y. The fourth line is wrong, because you cannot declare a reference to an r-value.

When you use auto, it is important to make sure that your reference type is correct. Just because the right-hand side is a reference, it doesn’t mean that the declared variable will be a reference, you have to specifically ask it to be.

The standard

Finally, what does the standard say about the type of a variable declared using auto. For a type declared

auto i = expr;

the type of i is the inferred type of u after the function call f(expr), given the following definition

template <class U> void f(U& u);

From → Language

  1. The solution to the const iterator issue is easily fixable, by ssimply using cbegin and cend:

    f(Container& c)
    auto iter = c.cbegin();
    while (iter != c.cend())
    //do something here

    the types of I and f in your second example are always int and double, regardless of the platform; if you need unsigned and float, you must “tag” the numbers: 10u, 4.5f

    The reference problem is the same if don’t use auto:

    int x;
    int& y = x;
    int z = y;
    int& a = 5;

    z is not a reference, just a copy of y. The last line won’t compile.

    The return type issue is fixed in C++14: you can omit the trailing return type at all in most cases.

    So, honestly, I don’t consider auto harmful, just convenient.

  2. Actually there is a simple solution for the “const iterators” problem: Use c.cbegin() and c.cend() or (better but only in C++14) std::cbegin(c) and std::cend(c)

  3. Well there you go. I was trying to point out things to be careful of, rather than people thinking that auto is some magical keyword that solves everything. Its behaviour is well defined, like everything that is defined by the standard, but if you don’t know what it is, then it is easy to get wrong. We have a tool that lets us blow our whole foot off, or something like that.

  4. I’ve edited the post to fix my forgetting that cbegin existed.

  5. ‘auto’ is very useful, but for more complicated expressions. For such simple expression as ‘int a = 0’ I would not use ‘auto’;

    There is a longer discussion here at Herb’s site:

    • Of course, I would not use it for int either. Yes, it is useful for very complicated expressions. I am just suggesting that it be used with care. Thanks for the link.

  6. Point-by-point answer:

    “const iterators” – That’s why C++11 has cbegin() and cend().

    “What size type do you want?” – Use type suffixes; 10u and 4.5f. I would strongly suggest doing that anyway.

    “What are my types?” – This argument is fundamentally at odds with the established programming advice “program to an interface, not an implementation”. That said, I don’t think that the concern completely meritless but in practice it often isn’t an issue, and it’s even beneficial to be type agnostic. C++ already does that with templates, and all OOP languages do it with interfaces/base classes.

    “What is my return type?” – This point is correct but it’s unrelated to use of auto: you would use such code when you cannot write the return type otherwise. In other words, in this case you don’t have a choice anyway. And yes, it’s not an ideal situation, which is why C++14 adds return type deduction.

    “To reference, or not to reference?” – This can be alleviated greatly by using universal references. But in general, you always have to think about references, auto or no auto.

    Many of these points have already been addressed in great detail by Herb Sutter in GotW #94 (aka. “AAA”). In fact, AAA’s discussion is so complete that, at this point, I believe that any discussion of auto more or less has to refer to this article, and its arguments.

Leave a Reply

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

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

Google photo

You are commenting using your Google 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 )

Connecting to %s

%d bloggers like this: