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.
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;...
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:
It hurts readability
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."
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.
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 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!
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
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();
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:
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.
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 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<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
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.
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
Related
It seems that auto was a fairly significant feature to be added in C++11 that seems to follow a lot of the newer languages. As with a language like Python, I have not seen any explicit variable declaration (I am not sure if it is possible using Python standards).
Is there a drawback to using auto to declare variables instead of explicitly declaring them?
The question is about drawbacks of auto, so this answer highlights some of those. A drawback of using a programming language feature (in this case, a facility associated with a language keyword) does not mean that feature is unacceptable, nor does it mean that feature should be avoided entirely. It means there are disadvantages along with advantages, so a decision to use auto type deduction over alternatives must consider engineering trade-offs.
When used well, auto has several advantages as well - which is not the subject of the question. The drawbacks result from ease of abuse, and from increased potential for code to behave in unintended or unexpected ways.
The main drawback is that, by using auto, you don't necessarily know the type of object being created. There are also occasions where the programmer might expect the compiler to deduce one type, but the compiler adamantly deduces another.
Given a declaration like
auto result = CallSomeFunction(x,y,z);
you don't necessarily have knowledge of what type result is. It might be an int. It might be a pointer. It might be something else. All of those support different operations. You can also dramatically change the code by a minor change like
auto result = CallSomeFunction(a,y,z);
because, depending on what overloads exist for CallSomeFunction() the type of result might be completely different - and subsequent code may therefore behave completely differently than intended. You might suddenly trigger error messages in later code(e.g. subsequently trying to dereference an int, trying to change something which is now const). The more sinister change is where your change sails past the compiler, but subsequent code behaves in different and unknown - possibly buggy - ways. For example (as noted by sashoalm in comments) if the deduced type of a variable changes an integral type to a floating point type - and subsequent code is unexpectedly and silently affected by loss of precision.
Not having explicit knowledge of the type of some variables therefore makes it harder to rigorously justify a claim that the code works as intended. This means more effort to justify claims of "fit for purpose" in high-criticality (e.g. safety-critical or mission-critical) domains.
The other, more common drawback, is the temptation for a programmer to use auto as a blunt instrument to force code to compile, rather than thinking about what the code is doing, and working to get it right.
This isn't a drawback of auto in a principled way exactly, but in practical terms it seems to be an issue for some. Basically, some people either: a) treat auto as a savior for types and shut their brain off when using it, or b) forget that auto always deduces to value types. This causes people to do things like this:
auto x = my_obj.method_that_returns_reference();
Oops, we just deep copied some object. It's often either a bug or a performance fail. Then, you can swing the other way too:
const auto& stuff = *func_that_returns_unique_ptr();
Now you get a dangling reference. These problems aren't caused by auto at all, so I don't consider them legitimate arguments against it. But it does seem like auto makes these issue more common (from my personal experience), for the reasons I listed at the beginning.
I think given time people will adjust, and understand the division of labor: auto deduces the underlying type, but you still want to think about reference-ness and const-ness. But it's taking a bit of time.
Other answers are mentioning drawbacks like "you don't really know what the type of a variable is." I'd say that this is largely related to sloppy naming convention in code. If your interfaces are clearly-named, you shouldn't need to care what the exact type is. Sure, auto result = callSomeFunction(a, b); doesn't tell you much. But auto valid = isValid(xmlFile, schema); tells you enough to use valid without having to care what its exact type is. After all, with just if (callSomeFunction(a, b)), you wouldn't know the type either. The same with any other subexpression temporary objects. So I don't consider this a real drawback of auto.
I'd say its primary drawback is that sometimes, the exact return type is not what you want to work with. In effect, sometimes the actual return type differs from the "logical" return type as an implementation/optimisation detail. Expression templates are a prime example. Let's say we have this:
SomeType operator* (const Matrix &lhs, const Vector &rhs);
Logically, we would expect SomeType to be Vector, and we definitely want to treat it as such in our code. However, it is possible that for optimisation purposes, the algebra library we're using implements expression templates, and the actual return type is this:
MultExpression<Matrix, Vector> operator* (const Matrix &lhs, const Vector &rhs);
Now, the problem is that MultExpression<Matrix, Vector> will in all likelihood store a const Matrix& and const Vector& internally; it expects that it will convert to a Vector before the end of its full-expression. If we have this code, all is well:
extern Matrix a, b, c;
extern Vector v;
void compute()
{
Vector res = a * (b * (c * v));
// do something with res
}
However, if we had used auto here, we could get in trouble:
void compute()
{
auto res = a * (b * (c * v));
// Oops! Now `res` is referring to temporaries (such as (c * v)) which no longer exist
}
It makes your code a little harder, or tedious, to read.
Imagine something like that:
auto output = doSomethingWithData(variables);
Now, to figure out the type of output, you'd have to track down signature of doSomethingWithData function.
One of the drawbacks is that sometimes you can't declare const_iterator with auto. You will get ordinary (non const) iterator in this example of code taken from this question:
map<string,int> usa;
//...init usa
auto city_it = usa.find("New York");
Like this developer, I hate auto. Or rather, I hate how people misuse auto.
I'm of the (strong) opinion that auto is for helping you write generic code, not for reducing typing.
C++ is a language whose goal is to let you write robust code, not to minimize development time.
This is fairly obvious from many features of C++, but unfortunately a few of the newer ones like auto that reduce typing mislead people into thinking they should start being lazy with typing.
In pre-auto days, people used typedefs, which was great because typedef allowed the designer of the library to help you figure out what the return type should be, so that their library works as expected. When you use auto, you take away that control from the class's designer and instead ask the compiler to figure out what the type should be, which removes one of the most powerful C++ tools from the toolbox and risks breaking their code.
Generally, if you use auto, it should be because your code works for any reasonable type, not because you're just too lazy to write down the type that it should work with.
If you use auto as a tool to help laziness, then what happens is that you eventually start introducing subtle bugs in your program, usually caused by implicit conversions that did not happen because you used auto.
Unfortunately, these bugs are difficult to illustrate in a short example here because their brevity makes them less convincing than the actual examples that come up in a user project -- however, they occur easily in template-heavy code that expect certain implicit conversions to take place.
If you want an example, there is one here. A little note, though: before being tempted to jump and criticize the code: keep in mind that many well-known and mature libraries have been developed around such implicit conversions, and they are there because they solve problems that can be difficult if not impossible to solve otherwise. Try to figure out a better solution before criticizing them.
auto does not have drawbacks per se, and I advocate to (hand-wavily) use it everywhere in new code. It allows your code to consistently type-check, and consistently avoid silent slicing. (If B derives from A and a function returning A suddenly returns B, then auto behaves as expected to store its return value)
Although, pre-C++11 legacy code may rely on implicit conversions induced by the use of explicitly-typed variables. Changing an explicitly-typed variable to auto might change code behaviour, so you'd better be cautious.
Keyword auto simply deduce the type from the return value. Therefore, it is not equivalent with a Python object, e.g.
# Python
a
a = 10 # OK
a = "10" # OK
a = ClassA() # OK
// C++
auto a; // Unable to deduce variable a
auto a = 10; // OK
a = "10"; // Value of const char* can't be assigned to int
a = ClassA{} // Value of ClassA can't be assigned to int
a = 10.0; // OK, implicit casting warning
Since auto is deduced during compilation, it won't have any drawback at runtime whatsoever.
What no one mentioned here so far, but for itself is worth an answer if you asked me.
Since (even if everyone should be aware that C != C++) code written in C can easily be designed to provide a base for C++ code and therefore be designed without too much effort to be C++ compatible, this could be a requirement for design.
I know about some rules where some well defined constructs from C are invalid for C++ and vice versa. But this would simply result in broken executables and the known UB-clause applies which most times is noticed by strange loopings resulting in crashes or whatever (or even may stay undetected, but that doesn't matter here).
But auto is the first time1 this changes!
Imagine you used auto as storage-class specifier before and transfer the code. It would not even necessarily (depending on the way it was used) "break"; it actually could silently change the behaviour of the program.
That's something one should keep in mind.
1At least the first time I'm aware of.
As I described in this answer auto can sometimes result in funky situations you didn't intend.
You have to explictly say auto& to have a reference type while doing just auto can create a pointer type. This can result in confusion by omitting the specifier all together, resulting in a copy of the reference instead of an actual reference.
One reason that I can think of is that you lose the opportunity to coerce the class that is returned. If your function or method returned a long 64 bit, and you only wanted a 32 unsigned int, then you lose the opportunity to control that.
I think auto is good when used in a localized context, where the reader easily & obviously can deduct its type, or well documented with a comment of its type or a name that infer the actual type. Those who don't understand how it works might take it in the wrong ways, like using it instead of template or similar. Here are some good and bad use cases in my opinion.
void test (const int & a)
{
// b is not const
// b is not a reference
auto b = a;
// b type is decided by the compiler based on value of a
// a is int
}
Good Uses
Iterators
std::vector<boost::tuple<ClassWithLongName1,std::vector<ClassWithLongName2>,int> v();
..
std::vector<boost::tuple<ClassWithLongName1,std::vector<ClassWithLongName2>,int>::iterator it = v.begin();
// VS
auto vi = v.begin();
Function Pointers
int test (ClassWithLongName1 a, ClassWithLongName2 b, int c)
{
..
}
..
int (*fp)(ClassWithLongName1, ClassWithLongName2, int) = test;
// VS
auto *f = test;
Bad Uses
Data Flow
auto input = "";
..
auto output = test(input);
Function Signature
auto test (auto a, auto b, auto c)
{
..
}
Trivial Cases
for(auto i = 0; i < 100; i++)
{
..
}
Another irritating example:
for (auto i = 0; i < s.size(); ++i)
generates a warning (comparison between signed and unsigned integer expressions [-Wsign-compare]), because i is a signed int. To avoid this you need to write e.g.
for (auto i = 0U; i < s.size(); ++i)
or perhaps better:
for (auto i = 0ULL; i < s.size(); ++i)
I'm surprised nobody has mentioned this, but suppose you are calculating the factorial of something:
#include <iostream>
using namespace std;
int main() {
auto n = 40;
auto factorial = 1;
for(int i = 1; i <=n; ++i)
{
factorial *= i;
}
cout << "Factorial of " << n << " = " << factorial <<endl;
cout << "Size of factorial: " << sizeof(factorial) << endl;
return 0;
}
This code will output this:
Factorial of 40 = 0
Size of factorial: 4
That was definetly not the expected result. That happened because auto deduced the type of the variable factorial as int because it was assigned to 1.
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.
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;...
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:
It hurts readability
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."
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.
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 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!
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
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();
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:
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.
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 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<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
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.
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
It seems that auto was a fairly significant feature to be added in C++11 that seems to follow a lot of the newer languages. As with a language like Python, I have not seen any explicit variable declaration (I am not sure if it is possible using Python standards).
Is there a drawback to using auto to declare variables instead of explicitly declaring them?
The question is about drawbacks of auto, so this answer highlights some of those. A drawback of using a programming language feature (in this case, a facility associated with a language keyword) does not mean that feature is unacceptable, nor does it mean that feature should be avoided entirely. It means there are disadvantages along with advantages, so a decision to use auto type deduction over alternatives must consider engineering trade-offs.
When used well, auto has several advantages as well - which is not the subject of the question. The drawbacks result from ease of abuse, and from increased potential for code to behave in unintended or unexpected ways.
The main drawback is that, by using auto, you don't necessarily know the type of object being created. There are also occasions where the programmer might expect the compiler to deduce one type, but the compiler adamantly deduces another.
Given a declaration like
auto result = CallSomeFunction(x,y,z);
you don't necessarily have knowledge of what type result is. It might be an int. It might be a pointer. It might be something else. All of those support different operations. You can also dramatically change the code by a minor change like
auto result = CallSomeFunction(a,y,z);
because, depending on what overloads exist for CallSomeFunction() the type of result might be completely different - and subsequent code may therefore behave completely differently than intended. You might suddenly trigger error messages in later code(e.g. subsequently trying to dereference an int, trying to change something which is now const). The more sinister change is where your change sails past the compiler, but subsequent code behaves in different and unknown - possibly buggy - ways. For example (as noted by sashoalm in comments) if the deduced type of a variable changes an integral type to a floating point type - and subsequent code is unexpectedly and silently affected by loss of precision.
Not having explicit knowledge of the type of some variables therefore makes it harder to rigorously justify a claim that the code works as intended. This means more effort to justify claims of "fit for purpose" in high-criticality (e.g. safety-critical or mission-critical) domains.
The other, more common drawback, is the temptation for a programmer to use auto as a blunt instrument to force code to compile, rather than thinking about what the code is doing, and working to get it right.
This isn't a drawback of auto in a principled way exactly, but in practical terms it seems to be an issue for some. Basically, some people either: a) treat auto as a savior for types and shut their brain off when using it, or b) forget that auto always deduces to value types. This causes people to do things like this:
auto x = my_obj.method_that_returns_reference();
Oops, we just deep copied some object. It's often either a bug or a performance fail. Then, you can swing the other way too:
const auto& stuff = *func_that_returns_unique_ptr();
Now you get a dangling reference. These problems aren't caused by auto at all, so I don't consider them legitimate arguments against it. But it does seem like auto makes these issue more common (from my personal experience), for the reasons I listed at the beginning.
I think given time people will adjust, and understand the division of labor: auto deduces the underlying type, but you still want to think about reference-ness and const-ness. But it's taking a bit of time.
Other answers are mentioning drawbacks like "you don't really know what the type of a variable is." I'd say that this is largely related to sloppy naming convention in code. If your interfaces are clearly-named, you shouldn't need to care what the exact type is. Sure, auto result = callSomeFunction(a, b); doesn't tell you much. But auto valid = isValid(xmlFile, schema); tells you enough to use valid without having to care what its exact type is. After all, with just if (callSomeFunction(a, b)), you wouldn't know the type either. The same with any other subexpression temporary objects. So I don't consider this a real drawback of auto.
I'd say its primary drawback is that sometimes, the exact return type is not what you want to work with. In effect, sometimes the actual return type differs from the "logical" return type as an implementation/optimisation detail. Expression templates are a prime example. Let's say we have this:
SomeType operator* (const Matrix &lhs, const Vector &rhs);
Logically, we would expect SomeType to be Vector, and we definitely want to treat it as such in our code. However, it is possible that for optimisation purposes, the algebra library we're using implements expression templates, and the actual return type is this:
MultExpression<Matrix, Vector> operator* (const Matrix &lhs, const Vector &rhs);
Now, the problem is that MultExpression<Matrix, Vector> will in all likelihood store a const Matrix& and const Vector& internally; it expects that it will convert to a Vector before the end of its full-expression. If we have this code, all is well:
extern Matrix a, b, c;
extern Vector v;
void compute()
{
Vector res = a * (b * (c * v));
// do something with res
}
However, if we had used auto here, we could get in trouble:
void compute()
{
auto res = a * (b * (c * v));
// Oops! Now `res` is referring to temporaries (such as (c * v)) which no longer exist
}
It makes your code a little harder, or tedious, to read.
Imagine something like that:
auto output = doSomethingWithData(variables);
Now, to figure out the type of output, you'd have to track down signature of doSomethingWithData function.
One of the drawbacks is that sometimes you can't declare const_iterator with auto. You will get ordinary (non const) iterator in this example of code taken from this question:
map<string,int> usa;
//...init usa
auto city_it = usa.find("New York");
Like this developer, I hate auto. Or rather, I hate how people misuse auto.
I'm of the (strong) opinion that auto is for helping you write generic code, not for reducing typing.
C++ is a language whose goal is to let you write robust code, not to minimize development time.
This is fairly obvious from many features of C++, but unfortunately a few of the newer ones like auto that reduce typing mislead people into thinking they should start being lazy with typing.
In pre-auto days, people used typedefs, which was great because typedef allowed the designer of the library to help you figure out what the return type should be, so that their library works as expected. When you use auto, you take away that control from the class's designer and instead ask the compiler to figure out what the type should be, which removes one of the most powerful C++ tools from the toolbox and risks breaking their code.
Generally, if you use auto, it should be because your code works for any reasonable type, not because you're just too lazy to write down the type that it should work with.
If you use auto as a tool to help laziness, then what happens is that you eventually start introducing subtle bugs in your program, usually caused by implicit conversions that did not happen because you used auto.
Unfortunately, these bugs are difficult to illustrate in a short example here because their brevity makes them less convincing than the actual examples that come up in a user project -- however, they occur easily in template-heavy code that expect certain implicit conversions to take place.
If you want an example, there is one here. A little note, though: before being tempted to jump and criticize the code: keep in mind that many well-known and mature libraries have been developed around such implicit conversions, and they are there because they solve problems that can be difficult if not impossible to solve otherwise. Try to figure out a better solution before criticizing them.
auto does not have drawbacks per se, and I advocate to (hand-wavily) use it everywhere in new code. It allows your code to consistently type-check, and consistently avoid silent slicing. (If B derives from A and a function returning A suddenly returns B, then auto behaves as expected to store its return value)
Although, pre-C++11 legacy code may rely on implicit conversions induced by the use of explicitly-typed variables. Changing an explicitly-typed variable to auto might change code behaviour, so you'd better be cautious.
Keyword auto simply deduce the type from the return value. Therefore, it is not equivalent with a Python object, e.g.
# Python
a
a = 10 # OK
a = "10" # OK
a = ClassA() # OK
// C++
auto a; // Unable to deduce variable a
auto a = 10; // OK
a = "10"; // Value of const char* can't be assigned to int
a = ClassA{} // Value of ClassA can't be assigned to int
a = 10.0; // OK, implicit casting warning
Since auto is deduced during compilation, it won't have any drawback at runtime whatsoever.
What no one mentioned here so far, but for itself is worth an answer if you asked me.
Since (even if everyone should be aware that C != C++) code written in C can easily be designed to provide a base for C++ code and therefore be designed without too much effort to be C++ compatible, this could be a requirement for design.
I know about some rules where some well defined constructs from C are invalid for C++ and vice versa. But this would simply result in broken executables and the known UB-clause applies which most times is noticed by strange loopings resulting in crashes or whatever (or even may stay undetected, but that doesn't matter here).
But auto is the first time1 this changes!
Imagine you used auto as storage-class specifier before and transfer the code. It would not even necessarily (depending on the way it was used) "break"; it actually could silently change the behaviour of the program.
That's something one should keep in mind.
1At least the first time I'm aware of.
As I described in this answer auto can sometimes result in funky situations you didn't intend.
You have to explictly say auto& to have a reference type while doing just auto can create a pointer type. This can result in confusion by omitting the specifier all together, resulting in a copy of the reference instead of an actual reference.
One reason that I can think of is that you lose the opportunity to coerce the class that is returned. If your function or method returned a long 64 bit, and you only wanted a 32 unsigned int, then you lose the opportunity to control that.
I think auto is good when used in a localized context, where the reader easily & obviously can deduct its type, or well documented with a comment of its type or a name that infer the actual type. Those who don't understand how it works might take it in the wrong ways, like using it instead of template or similar. Here are some good and bad use cases in my opinion.
void test (const int & a)
{
// b is not const
// b is not a reference
auto b = a;
// b type is decided by the compiler based on value of a
// a is int
}
Good Uses
Iterators
std::vector<boost::tuple<ClassWithLongName1,std::vector<ClassWithLongName2>,int> v();
..
std::vector<boost::tuple<ClassWithLongName1,std::vector<ClassWithLongName2>,int>::iterator it = v.begin();
// VS
auto vi = v.begin();
Function Pointers
int test (ClassWithLongName1 a, ClassWithLongName2 b, int c)
{
..
}
..
int (*fp)(ClassWithLongName1, ClassWithLongName2, int) = test;
// VS
auto *f = test;
Bad Uses
Data Flow
auto input = "";
..
auto output = test(input);
Function Signature
auto test (auto a, auto b, auto c)
{
..
}
Trivial Cases
for(auto i = 0; i < 100; i++)
{
..
}
Another irritating example:
for (auto i = 0; i < s.size(); ++i)
generates a warning (comparison between signed and unsigned integer expressions [-Wsign-compare]), because i is a signed int. To avoid this you need to write e.g.
for (auto i = 0U; i < s.size(); ++i)
or perhaps better:
for (auto i = 0ULL; i < s.size(); ++i)
I'm surprised nobody has mentioned this, but suppose you are calculating the factorial of something:
#include <iostream>
using namespace std;
int main() {
auto n = 40;
auto factorial = 1;
for(int i = 1; i <=n; ++i)
{
factorial *= i;
}
cout << "Factorial of " << n << " = " << factorial <<endl;
cout << "Size of factorial: " << sizeof(factorial) << endl;
return 0;
}
This code will output this:
Factorial of 40 = 0
Size of factorial: 4
That was definetly not the expected result. That happened because auto deduced the type of the variable factorial as int because it was assigned to 1.
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.
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;...
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:
It hurts readability
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."
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.
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 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!
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
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();
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:
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.
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 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<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
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.
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
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How much is too much with C++0x auto keyword
Have we (as a community) had enough experience to determine when and/or whether auto is being abused?
What I am really looking for is a best practices guide on
when to use auto
when it should be avoided
Simple rules of thumb that can quickly be followed in 80% of cases.
As a context this question is sparked by my response here
I think when the type is very well-known amongst the co-programmers who work (or would work) in your project, then auto can be used, such as in the following code:
//good : auto increases readability here
for(auto it = v.begin(); it != v.end(); ++it) //v is some [std] container
{
//..
}
Or, more generally,
//good : auto increases readability here
for(auto it = std::begin(v); it != std::end(v); ++it)//v could be array as well
{
//..
}
But when the type is not very well-known and infrequently used , then I think auto seems to reduce readability, such as here:
//bad : auto decreases readability here
auto obj = ProcessData(someVariables);
While in the former case, the usage of auto seems very good and doesn't reduce readability, and therefore, can be used extensively, but in the latter case, it reduces readabilty and hence shouldn't be used.
Another place where auto can be used is when you use new1 or make_* functions , such as here:
//without auto. Not that good, looks cumbersome
SomeType<OtherType>::SomeOtherType * obj1 = new SomeType<OtherType>::SomeOtherType();
std::shared_ptr<XyzType> obj2 = std::make_shared<XyzType>(args...);
std::unique_ptr<XyzType> obj2 = std::make_unique<XyzType>(args...);
//With auto. good : auto increases readability here
auto obj1 = new SomeType<OtherType>::SomeOtherType();
auto obj2 = std::make_shared<XyzType>(args...);
auto obj3 = std::make_unique<XyzType>(args...);
Here it is very good, as it reduces the use of keyboard, without reducing the readability, as anyone can know the type of objects being created, just by looking at the code.
1. Avoid using new and raw-pointers though.
Sometime, the type is so irrelevant that the knowledge of the type is not even needed, such as in expression template; in fact, practically it is impossible to write the type (correctly), in such cases auto is a relief for programmers. I've written expression template library which can be used as:
foam::composition::expression<int> x;
auto s = x * x; //square
auto c = x * x * x; //cube
for(int i = 0; i < 5 ; i++ )
std::cout << s(i) << ", " << c(i) << std::endl;
Output:
0, 0
1, 1
4, 8
9, 27
16, 64
Now compare the above code with the following equivalent code which doesn't use auto:
foam::composition::expression<int> x;
//scroll horizontally to see the complete type!!
foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<int>, foam::composition::expression<int>, foam::operators::multiply>> s = x * x; //square
foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<int>, foam::composition::expression<int>, foam::operators::multiply> >, foam::composition::expression<int>, foam::operators::multiply>> c = x * x * x; //cube
for(int i = 0; i < 5 ; i++ )
std::cout << s(i) << ", " << c(i) << std::endl;
As you can see, in such cases auto makes your life exponentially easier. The expressions used above are very simple; think about the type of some more complex expressions:
auto a = x * x - 4 * x + 4;
auto b = x * (x + 10) / ( x * x+ 12 );
auto c = (x ^ 4 + x ^ 3 + x ^ 2 + x + 100 ) / ( x ^ 2 + 10 );
The type of such expressions would be even more huge and ugly, but thanks to auto, we now can let the compiler infer the type of the expressions.
So the bottomline is: the keyword auto might increase or decrease clarity and readability of your code, depending on the context. If the context makes it clear what type it is, or at least how it should be used (in case of standard container iterator) or the knowledge of the actual type is not even needed (such as in expression templates), then auto should be used, and if the context doesn't make it clear and isn't very common (such as the second case above), then it should better be avoided.
Easy. Use it when you don't care what the type is. For example
for (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.
I’d apply the same rule as for var in C#: use it liberally. It increases readability. Unless the type of a variable is actually important enough to be stated explicitly, in which cases this should be done (duh).
Still, I maintain that (especially in statically typed languages) the compiler is much better at tracking types for us than we are. Most of the time, the exact type isn’t terribly important anyway (otherwise interfaces wouldn’t work in practice). It’s more important to be aware of which operations are permitted. Context should tell us that.
Furthermore, auto can actually prevent bugs, by preventing unwanted implicit conversions in initialisations. Generally, the statement Foo x = y; will perform an implicit conversion if y isn’t of type Foo and an implicit conversion exists. This is the reason to avoid having implicit conversions in the first place. Unfortunately, C++ has much too many of them already.
Writing auto x = y; will prevent this problem in principle.
On the other hand, it should be clear that when I’m performing calculations that assume this or that number of bytes in an integer, the explicit type of the variable must be known and should be clearly stated.
Not all cases are as clear cut but I maintain that most are, and that
in most cases it’s easy to see whether an explicit type needs to be known, and
the need for explicit types is comparatively rare.
Eric Lippert, principal developer on the C# compiler team, has stated much the same with regards to var.
I think the answer to your first question is sort of no. We know enough to put together some guidelines about when to use or avoid auto, but they still leave quite a few cases where the best we can currently say is that we can't yet give much in the way of objective advice about them.
The obvious case where you nearly have to use it is in a template when you want (for example) the proper type to hold the result of some operation on two generic parameters. In a case like this, the only possibility of abuse wouldn't really be abuse of auto itself, but whether the general type of operation you're doing (or type of template you're writing, etc.) is something you'd be better off avoiding.
There are also at least a few situations where you clearly need to avoid auto. If you're using something like a proxy type where you're depending on the conversion from proxy->target to do part of the job at hand, auto will (attempt to) create a target of the same type as the source so that conversion won't happen. In some cases, that may just delay the conversion, but in others it won't work at all (e.g., if the proxy type doesn't support assignment, which is often the case).
Another example would be when you need to assure that a particular variable has a specific type for the sake of something like an external interface. Just for example, consider applying the network mask to an IP (v4) address. For the sake of argument, let's assume you're working with the individual octets of the address (e.g., representing each as an unsigned char), so we end up with something like octets[0] & mask[0]. Thanks to C's type promotion rules, even if both operands are unsigned chars, the result is typically going to be int. We need the result to be an unsigned char though (i.e., one octet) not an int (typically 4 octets) though. As such, in this situation, auto would almost certainly be inappropriate.
That still leaves a lot of cases where it's a judgement call though. My own tendency for these cases is to treat auto as the default, and only use an explicit type in cases that are at least a little like the latter case I've cited above -- even if a particular type isn't needed for correct operation that I really want a particular type, even if that might involve an implicit conversion.
My guess (but it is just a guess) is that over time, I'll probably tend even more in that direction. As I get more accustomed to the compiler picking out types, I'll find that a fair number of cases where I currently think I should specify the type, I really don't need to and the code will be just fine.
I suspect a lot of us (and the older/more experienced we are, probably the worse we'll be about it) will use explicit types for reasons that ultimately trace back to some feeling about performance, and believing that our choice will improve performance. Part of the time we may even be right -- but as most of us with that much experience have found, our guesses are often wrong (especially when they're based on implicit assumptions), and compilers and processors generally get better at such things over time as well.
I've used languages with full type inference. I see no reason not to put auto everywhere it's technically possible*. In fact I may have already written auto i = 0;, where int is one character shorter than auto. I'm not even sure that I did because the bottom is: I don't care for manifest typing.
*: for instance auto int[] = { 0, 1, 2, 3 } doesn't work.
Only use it with long repetitive types such as long templates and lambda function types. Try to avoid it if you can to make things clear.