logo

C++ Keywords - auto

auto: the type of the variable will be automatically deduced.

Use cases

auto can be overused. If the type is not obvious, prefer to specify the full type instead of using auto.

Some acceptable usages are listed below.

In loops

// Without auto
for (const std::pair<const std::string, double>& entry : my_map) {
  printf("%f\n", entry.second);
}

// With auto
for (const auto& entry : my_map) {
  printf("%f\n", entry.second);
}

// With auto and structured bindings
for (const auto& [key, value] : my_map) {
  printf("%f\n", value);
}

Iterators

// Without auto
absl::flat_hash_map<std::string, int>::const_iterator iter = m.find(val);

// With auto
auto iter = m.find(val);

unique_ptr

// Without auto
std::unique_ptr ptr = std::make_unique<int>(10);

// With auto
auto ptr = std::make_unique<int>(10);

Best Practice

Be precise

Be precise with use of auto. Knowing that things are constant or that indirections are occurring is very valuable information to readers.

  • auto / const auto
  • auto& / const auto&: a reference to non-const / const
  • auto* / const auto*: when the type is a pointer.

auto For returned unique_ptr

If GetFoo returns unique_ptr<Foo>:

These 2 are equivalent:

  • const auto foo = GetFoo(); (Preferred)
  • const auto& foo = GetFoo();

This does not compile.

  • const auto* foo = GetFoo();

auto* x = y expects that y is a C++ pointer. But std::unique_ptr<T> is just an object that behaves like a pointer and takes care of ownership. Other than that, it is just a regular C++ class, not a regular pointer, like int*.

Do not do:

  • const auto* foo = GetFoo().get();

It destructs the pointer when the statement ends, leaving thing as a dangling pointer.

GetFoo will return a temporary object, you get the pointer to the underlying Foo* and assign it to foo. However as soon as that line is execute, the temporary unique_ptr will be destroyed and the underlying Foo object is freed, so now foo is a dangling pointer to the freed memory.