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.
Side note: This question was moved to SE.Programmers and then back to Stack Overflow. Discussion about this can be found in this meta question .
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)
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.
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;...
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.
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 :
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."
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();
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.
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 eg
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 eg 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!
One danger I have noted is in terms of references. eg
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();
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:
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.
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:
And also:
auto
with the concrete type.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!
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 ie auto forces you to initialize a variable hence you can't forget doing that.
When it should not be used or Cons of auto
std::vector<bool> 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
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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.