Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a downside to declaring variables with auto in C++?

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?

like image 226
DxAlpha Avatar asked Jan 13 '16 03:01

DxAlpha


People also ask

Should you use Auto?

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 new 1 or make_* functions , such as here: //without auto.

When should I use Auto?

The auto keyword is a simple way to declare a variable that has a complicated type. For example, you can use auto to declare a variable where the initialization expression involves templates, pointers to functions, or pointers to members.

Can I use Auto in C?

C language uses 4 storage classes, namely: auto: This is the default storage class for all the variables declared inside a function or a block. Hence, the keyword auto is rarely used while writing programs in C language.

Is it OK to use auto in C++?

Automatic type deduction is one of the most important and widely used features in modern C++. The new C++ standards have made it possible to use auto as a placeholder for types in various contexts and let the compiler deduce the actual type.


10 Answers

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.

like image 119
Peter Avatar answered Oct 03 '22 20:10

Peter


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.

like image 37
Nir Friedman Avatar answered Oct 04 '22 20:10

Nir Friedman


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
}
like image 32
Angew is no longer proud of SO Avatar answered Oct 04 '22 20:10

Angew is no longer proud of SO


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.

like image 31
Skam Avatar answered Sep 30 '22 20:09

Skam


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 image 28
ks1322 Avatar answered Oct 01 '22 20:10

ks1322


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.

like image 22
user541686 Avatar answered Sep 30 '22 20:09

user541686


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.

like image 41
Laurent LA RIZZA Avatar answered Oct 03 '22 20:10

Laurent LA RIZZA


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.

like image 21
Leben Asa Avatar answered Oct 01 '22 20:10

Leben Asa


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.

like image 40
dhein Avatar answered Sep 30 '22 20:09

dhein


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.

like image 2
Hatted Rooster Avatar answered Oct 04 '22 20:10

Hatted Rooster