Is There a Downside to Declaring Variables with Auto in C++

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

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)

Is there any reason to use the 'auto' keyword in C++03?

auto is a storage class specifier, static, register and extern too. You can only use one of these four in a declaration.

Local variables (without static) have automatic storage duration, which means they live from the start of their definition until the end of their block. Putting auto in front of them is redundant since that is the default anyway.

I don't know of any reason to use it in C++. In old C versions that have the implicit int rule, you could use it to declare a variable, like in:

int main(void) { auto i = 1; }

To make it valid syntax or disambiguate from an assignment expression in case i is in scope. But this doesn't work in C++ anyway (you have to specify a type). Funny enough, the C++ Standard writes:

An object declared without a storage-class-specifier at block scope or declared as a function parameter has automatic storage duration by default. [Note: hence, the auto specifier is almost always redundant and not often used; one use of auto is to distinguish a declaration-statement from an expression-statement (6.8) explicitly. — end note]

which refers to the following scenario, which could be either a cast of a to int or the declaration of a variable a of type int having redundant parentheses around a. It is always taken to be a declaration, so auto wouldn't add anything useful here, but would for the human, instead. But then again, the human would be better off removing the redundant parentheses around a, I would say:

int(a);

With the new meaning of auto arriving with C++0x, I would discourage using it with C++03's meaning in code.

The new keyword auto; When should it be used to declare a variable type?

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.

Why do I need to explicitly write the 'auto' keyword?

Dropping the explicit auto would break the language:

e.g.

int main()
{
int n;
{
auto n = 0; // this shadows the outer n.
}
}

where you can see that dropping the auto would not shadow the outer n.

What's the reason for auto keyword in pure C?

All variables are not auto by default; anything declared at file scope is static, for example.

The auto keyword is a holdover from the BCPL and B languages, from which C was derived. It is largely vestigial at this point, but by that same token it doesn't do any harm, so there's no reason to get rid of it, either.

Concept of auto keyword in c

auto isn't a datatype. It's a storage class specifier, like static. It's basically the opposite of static when used on local variables and indicates that the variable's lifetime is equal to its scope (for example: when it goes out of scope it is automatically destroyed).

You never need to specify auto as the only places you're allowed to use it it is also the default.



Related Topics



Leave a reply



Submit