How much is too much with C++11 auto keyword?

C++TypesC++11Type InferenceAuto

C++ Problem Overview


I've been using the new auto keyword available in the C++11 standard for complicated templated types which is what I believe it was designed for. But I'm also using it for things like:

auto foo = std::make_shared<Foo>();

And more skeptically for:

auto foo = bla(); // where bla() return a shared_ptr<Foo>

I haven't seen much discussion on this topic. It seems that auto could be overused since a type is often a form of documentation and sanity checks. Where do you draw the line in using auto and what are the recommended use cases for this new feature?

To clarify: I'm not asking for a philosophical opinion; I'm asking for the intended use of this keyword by the standard committee, possibly with comments on how that intended use is realized in practice.

C++ Solutions


Solution 1 - C++

I think that one should use the auto keyword whenever it's hard to say how to write the type at first sight, but the type of the right hand side of an expression is obvious. For example, using:

my_multi_type::nth_index<2>::type::key_type::composite_key_type::
    key_extractor_tuple::tail_type::head_type::result_type

to get the composite key type in boost::multi_index, even though you know that it is int. You can't just write int because it could be changed in the future. I would write auto in this case.

So if the auto keyword improves readability in a particular case then use it. You can write auto when it is obvious to the reader what type auto represents.

Here are some examples:

auto foo = std::make_shared<Foo>();   // obvious
auto foo = bla();                     // unclear. don't know which type `foo` has

const size_t max_size = 100;
for ( auto x = max_size; x > 0; --x ) // unclear. could lead to the errors
                                      // since max_size is unsigned

std::vector<some_class> v;
for ( auto it = v.begin(); it != v.end(); ++it )
                                      // ok, since I know that `it` has an iterator type
                                      // (don't really care which one in this context)

Solution 2 - C++

Use auto everywhere you can—particularly const auto so that side effects are less of a concern. You won’t have to worry about types except in the obvious cases, but they’ll still be statically verified for you, and you can avoid some repetition. Where auto isn't feasible, you can use decltype to express types semantically as contracts based on expressions. Your code will look different, but it will be a positive change.

Solution 3 - C++

Easy. Use it when you don't care what the type is. For example

for (const auto & i : some_container) {
   ...

All I care about here is that i is whatever's in the container.

It's a bit like typedefs.

typedef float Height;
typedef double Weight;
//....
Height h;
Weight w;

Here, I don't care whether h and w are floats or doubles, only that they are whatever type is suitable to express heights and weights.

Or consider

for (auto i = some_container .begin (); ...

Here all I care about is that it's a suitable iterator, supporting operator++(), it's kind of like duck typing in this respect.

Also the type of lambdas can't be spelled, so auto f = []... is good style. The alternative is casting to std::function but that comes with overhead.

I can't really conceive of an "abuse" of auto. The closest I can imagine is depriving yourself of an explicit conversion to some significant type -- but you wouldn't use auto for that, you'd construct an object of the desired type.

If you can remove some redundancy in your code without introducing side effects, then it must be good to do so.

Counterexamples (borrowed from someone else's answers):

auto i = SomeClass();
for (auto x = make_unsigned (y); ...)

Here we DO care what the type is, so we should write Someclass i; and for(unsigned x = y;...

Solution 4 - C++

Go for it. Use auto anywhere it makes writing code easier.

Every new feature in any language is going to get overused by at least some types of programmers. It is only through moderate overuse by some experienced programmers (not noobs) that the rest of the experienced programmers learn the boundaries of proper use. Extreme overuse is usually bad, but could be good because such overuse may lead to improvements in the feature or a better feature to replace it.

But if I were working on code with more than a few lines like

auto foo = bla();

where the type is indicated zero times, I might want to change those lines to include types. The first example is great since the type is stated once, and auto saves us from having to write messy templated types twice. Hooray for C++++. But explicitly showing the type zero times, if it's not easily visible in a nearby line, makes me nervous, at least in C++ and its immediate successors. For other languages designed to work at a higher level with more abstraction, polymorphism and genericity, it's fine.

Solution 5 - C++

At C++ and Beyond 2012 in the Ask Us Anything panel, there was a fantastic exchange between Andrei Alexandrescu, Scott Meyers and Herb Sutter talking about when to use and not use auto. Skip to minute 25:03 for a 4 minute discussion. All three speakers give excellent points that should be kept in mind for when to not use auto.

I highly encourage people to come to their own conclusion, but my take away was to use auto everywhere unless:

  1. It hurts readability
  2. There is concern about automatic type conversion (e.g. from constructors, assignment, template intermediate types, implicit conversion between integer widths)

Liberal use of explicit helps reduce concern for the latter, which helps minimize the amount of time the former is an issue.

Rephrasing what Herb said, "if you're not doing X, Y, and Z, use auto. Learn what X, Y, and Z are and go forth and use auto everywhere else."

Solution 6 - C++

Yes, it can be overused to the detriment of readability. I suggest using it in the contexts where exact types are long, or unutterable, or not important for readability, and variables are short-lived. For example, iterator type usually is long and isn't important, so auto would work:

   for(auto i = container.begin(); i != container.end(); ++i);

auto here doesn't hurt readability.

Another example is parser rule type, which can be long and convoluted. Compare:

   auto spaces = space & space & space;

with

r_and_t<r_and_t<r_char_t<char>&, r_char_t<char>&>, r_char_t<char>&> spaces = 
   space & space & space;

On the other hand, when type is known and is simple, it's much better if it stated explicitly:

int i = foo();

rather than

auto i = foo();

Solution 7 - C++

auto can be very dangerous in combination with expression templates which are used a lot by linear algebra libraries such as Eigen or OpenCV.

auto A = Matrix(...);
auto B = Matrix(...);
auto C = A * B; // C is not a matrix. It is a matrix EXPRESSION.
cout << C; // The expression is evaluated and gives the expected result.
... // <code modifying A or B>
cout << C; // The expression is evaluated AGAIN and gives a DIFFERENT result.

Bugs caused by this type of mistakes are a major pain to debug. One possible remedy is to explicitly cast the result to the expected type if you are hellbent on using auto for the left-to-right declaration style.

auto C = Matrix(A * B); // The expression is now evaluated immediately.

Solution 8 - C++

I use auto wihout restriction and didn't face any problem. I even sometimes end up using it for simple types like int. This makes c++ a higher level language for me, and allows to declare variable in c++ like in python. After writing python code, I even sometimes write e.g.

auto i = MyClass();

instead of

MyClass i;

This is one case where I would say it is an abuse of the auto keyword.

Often I don't mind what is the exact type of the object, I'm more interested in its fonctionality, and as function names generally say something about the objects they return, auto does not hurt: in e.g. auto s = mycollection.size(), I can guess that s will be a kind of integer, and in the rare case where I care about the exact type, let's check the function prototype then (I mean, I prefer to have to check when I need the info, rather than a priori when code is written, just in case it would be usefull someday, as in int_type s = mycollection.size()).

Concerning this example from the accepted answer:

for ( auto x = max_size; x > 0; --x )

In my code I still use auto in this case, and if I want x to be unsigned, then I use an utility function, named say make_unsigned, which expresses clearly my concerns:

for ( auto x = make_unsigned(max_size); x > 0; --x )

disclaimer: I just describe my use, I'm not competent to give advices!

Solution 9 - C++

One danger I have noted is in terms of references. e.g.

MyBigObject& ref_to_big_object= big_object;
auto another_ref = ref_to_big_object; // ?

The problem is another_ref is not actually a reference in this case it is MyBigObject instead of MyBigObject&. You end up copying a big object without realising it.

If you are getting a reference directly from a method you might not think about what it actually is.

auto another_ref = function_returning_ref_to_big_object();

you would need "auto&" or "const auto&"

MyBigObject& ref_to_big_object= big_object;
auto& another_ref = ref_to_big_object;
const auto& yet_another_ref = function_returning_ref_to_big_object();

Solution 10 - C++

One of the major problem with C++ program is it allows you to use the uninitialized variable. This leads us to nasty non deterministic program behavior. It should be noted that modern compiler now throw appropriate/message warning messages if program tires to use it.

Just to illustrate this, consider below c++ program:

int main() {
    int x;
	int y = 0;
	y += x;
}

If I compile this program using modern compiler(GCC), it gives the warning. Such warning may not be very obvious if we are working with the real complex production code.

> main.cpp: In function 'int main()': > > main.cpp:4:8: warning: 'x' is used uninitialized in this function > [-Wuninitialized] > > y += x; > > ^

================================================================================= Now if we change our program which uses auto, then compile we get the following:

int main() {
    auto x;
	auto y = 0;
	y += x;
}

> main.cpp: In function 'int main()': > > main.cpp:2:10: error: declaration of 'auto x' has no initializer > > auto x; > > ^

With auto, it is not possible to use the uninitialized variable. This is major advantage which we may get(for free), if we start using auto.

This concept and other great great modern C++ concept is explained by C++ expert Herb Shutter in his CppCon14 talk:

Back to the Basics! Essentials of Modern C++ Style

Solution 11 - C++

Use auto where it makes sense for a type to be inferred. If you have something that you know is an integer, or you know it's a string, just use int / std::string, etc. I wouldn't worry about "overusing" a language feature unless it gets to the point of ridiculousness, or obfuscates code.

That's my opinion anyway.

Solution 12 - C++

TL;DR: See rule-of-thumb at the bottom.

The accepted answer suggests the following rule of thumb:

> Use auto whenever it's hard to say how to write the type at first sight, but the type of the right hand side of an expression is obvious.

But I would say that's too restrictive. Sometime I don't care about the types, since the statement is informative enough without me bothering to take the time to figure the type out. What do I mean by that? Consider the example which has popped up in some of the answers:

auto x = f();

What makes this an example of misuse of auto? Is it my ignorance of f()'s return type? Well, it may indeed help if I did know it, but - that's not my main concern. What is much more of a problem is that x and f() are pretty meaningless. If we had:

auto nugget = mine_gold();

instead, then I usually don't care whether the return type of the function is obvious or not. Reading the statement, I know what I'm doing and I know enough about what the return value's semantics to not feel I need to also know its type.

So my answer is: Use auto whenever the compiler allows it, unless:

  • You feel the variable name together with the initialization / assignment expression do not provide enough information about what the statement is doing.
  • You feel the variable name together with the initialization / assignment expression provides "misleading" information about what the type should be - i.e., if you had to guess what comes instead of the auto you would be able to make a guess - and it would be wrong, and this false assumption has repercussions later in the code.
  • You want to force a different type (e.g. a reference).

And also:

  • Prefer giving a meaningful name (which does not contain the type name of course) before replacing auto with the concrete type.

Solution 13 - C++

auto keyword can only be used for local variable, not to arguments or class/struct members. So, it is safe and viable to use them anywhere you like. I do use them a lot. The type is deduced at compile time, the debugger shows the type while debugging, the sizeof reports it correctly, the decltype would give correct type - there is no harm. I don't count auto as overused, ever!

Solution 14 - C++

What auto does?

It tells compiler to infer(determine) the variable's data type based on its initialized value. It uses type deduction.

Where should auto be used?

  • When you are not interested in knowing the type of variable and just want to use it.

  • When you want to avoid incredibly long and ugly typenames.

  • When you are not sure of the type himself.

  • When you do not want to see uninitialized variables in your code i.e. auto forces you to initialize a variable hence you can’t forget doing that.

When it should not be used or Cons of auto

  • Referring to its functionality, auto may deduce type incorrectly, One such case is

> std::vector vec(10, 0); >
> auto x = vec[2]; >
> bool y = vec[2]; >
> std::cout << typeid(x).name() << "\n"; >
> std::cout << typeid(y).name() << "\n";

The output on G++ 10.2 is surprising:

St14_Bit_reference

b
  • It should not be used if you want to make your code readable & Understandable for other people. It hides the data type visibility from the reader.

Solution 15 - C++

One of my bitter experience with auto is using it with lambda expressions:

auto i = []() { return 0; };
cout<<"i = "<<i<<endl; // output: 1 !!!

Actually, here i is resolved to function pointer of int(*)(). This is just a simple cout, but just imagine what kind of bad compilation / runtime errors it can cause when used with template.

You should avoid auto with such expressions and put a proper return type (or controlled decltype())

Correct usage for above example would be,

auto i = []() { return 0; }(); // and now i contains the result of calling the lambda  

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlan TuringView Question on Stackoverflow
Solution 1 - C++Kirill V. LyadvinskyView Answer on Stackoverflow
Solution 2 - C++Jon PurdyView Answer on Stackoverflow
Solution 3 - C++spraffView Answer on Stackoverflow
Solution 4 - C++DarenWView Answer on Stackoverflow
Solution 5 - C++SeanView Answer on Stackoverflow
Solution 6 - C++Gene BushuyevView Answer on Stackoverflow
Solution 7 - C++morotspajView Answer on Stackoverflow
Solution 8 - C++rafakView Answer on Stackoverflow
Solution 9 - C++user2495422View Answer on Stackoverflow
Solution 10 - C++Mantosh KumarView Answer on Stackoverflow
Solution 11 - C++LainIwakuraView Answer on Stackoverflow
Solution 12 - C++einpoklumView Answer on Stackoverflow
Solution 13 - C++AjayView Answer on Stackoverflow
Solution 14 - C++TonyParkerView Answer on Stackoverflow
Solution 15 - C++iammilindView Answer on Stackoverflow