第 18.1 節

auto

0瀏覽次數0訪問次數--跳出率--平均停留

What problem does this section solve?

In C++, many type names are long, difficult to type, and easy to mistype, for example:

std::map<std::string, std::vector<int>>::const_iterator it = m.begin();
std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>();

Allow the compiler to automatically deduce types for us, reducing verbose type declarations to make code cleaner and easier to maintain.

What is this feature?

The auto keyword tells the compiler: "Please help me automatically deduce the type of this variable based on the initialized value." It doesn't weaken type safety — the deduced type is determined at compile time, so it remains strongly typed.

C++ standard version

C++11 (basic usage), C++14 added auto for function return type deduction, and C++17 introduced auto for use in scenarios like structured bindings.

Required header files

No additional header files are required. auto is a language keyword.

Basic Syntax

auto 变量名 = 表达式;        // 编译器根据表达式推导类型
const auto 变量名 = 表达式;  // 推导后加 const
auto& 变量名 = 表达式;       // 推导为引用类型
const auto& 变量名 = 表达式; // 推导为只读引用类型

Common Usage

|Usage|Explanation|Here is the translation of the provided Simplified Chinese Markdown fragment into natural American English, following all specified rules.


Example| |:---|:---|:---| |auto|Automatic value type deduction (loses references and const)|auto x = 42; → int| |const auto|Derived as a read-only type.|const auto s = "hello";| |auto&|Derived as reference (modifiable original value)|auto& x = vec[0];| |const auto&|Derive as read-only reference (no copy, no modification)|const auto& x = get_value();| |auto*|derived as a pointer|auto* p = &x;| |decltype(auto)|Perfect forwarding with reference and cv-qualifier preservation (C++14)|decltype(auto) x = get_ref();|

When to use which type

auto The most commonly misunderstood aspect is: it doesn't "automatically become the type you want", but rather deduces according to fixed rules. Especially when encountering references, const, or function return values, you must clearly write out your intent.

SceneRecommended Writing StyleReason
The local variable types are very obvious.auto x = expr;Avoid redundant types.
Traverse large objects in read-only mode.const auto& xAvoid copying, and do not allow modification
Modify the original objectauto& xGet the citation.
nullable pointerauto* p = get();Let the reader see at a glance that this is a pointer.
Functions return references and must retain referencesdecltype(auto)auto will lose its reference.
The type itself carries business meaning.Explicit TypeFor example Meter distance = ... is clearer than auto distance

Example code

Example 1: Basic Type Inference

#include <iostream>
#include <string>

int main()
{
    auto n = 42;              // int
    auto d = 3.14;            // double
    auto c = 'A';             // char
    auto s = "hello";         // const char*
    auto str = std::string("world");  // std::string

    std::cout << "n = " << n << "\n";
    std::cout << "d = " << d << "\n";
    std::cout << "c = " << c << "\n";
    std::cout << "str = " << str << "\n";

    return 0;
}

Results

n = 42
d = 3.14
c = A
str = world

Example 2: Building on Example 1, the difference between auto& and const auto&.

#include <iostream>

int main()
{
    int x = 10;

    auto a = x;         // a 是 int,拷贝了 x
    auto& b = x;        // b 是 int&,是 x 的引用
    const auto& c = x;  // c 是 const int&,只读引用

    a = 100;
    std::cout << "after a=100, x = " << x << "\n";  // x 不变

    b = 200;
    std::cout << "after b=200, x = " << x << "\n";  // x 变了

    // c = 300;  // ❌ 编译错误!c 是只读引用

    return 0;
}

Results

after a=100, x = 10
after b=200, x = 200

Example 3: Building on Example 2, use auto to simplify iterators and complex types

Using auto in C++ allows the compiler to deduce types automatically, which significantly reduces verbosity when working with complex types like iterators or deeply nested container types. Here’s how it simplifies the code from Example 2:

Example 2 (without auto):

std::map<std::string, std::vector<int>>::iterator it = myMap.begin();
while (it != myMap.end()) {
    std::vector<int> vec = it->second;
    for (std::vector<int>::iterator vecIt = vec.begin(); vecIt != vec.end(); ++vecIt) {
        std::cout << *vecIt << std::endl;
    }
    ++it;
}

Example 3 (with auto):

auto it = myMap.begin();
while (it != myMap.end()) {
    auto vec = it->second;
    for (auto vecIt = vec.begin(); vecIt != vec.end(); ++vecIt) {
        std::cout << *vecIt << std::endl;
    }
    ++it;
}

Key improvements:

  1. Iterator declarations become auto it = container.begin() instead of spelling out the full type.
  2. Complex nested types (like std::vector<int>::iterator) are inferred automatically.
  3. Code becomes more readable and less error-prone, especially when types are long or change.
  4. The underlying logic remains identical—auto only simplifies the syntax, not the behavior.

This is especially useful when working with templated or generic code where exact types might be cumbersome to write out explicitly.

#include <iostream>
#include <vector>
#include <map>
#include <memory>
#include <string>

int main()
{
    std::vector<std::string> names = {"Alice", "Bob", "Charlie"};

    // 不用 auto 的写法(类型名很长)
    for (std::vector<std::string>::const_iterator it = names.begin();
         it != names.end(); ++it)
    {
        std::cout << *it << " ";
    }
    std::cout << "\n";

    // 用 auto 简化(同样清晰)
    for (auto it = names.begin(); it != names.end(); ++it)
    {
        std::cout << *it << " ";
    }
    std::cout << "\n";

    // 智能指针用 auto 简化
    auto ptr = std::make_shared<int>(42);
    std::cout << "*ptr = " << *ptr << "\n";

    return 0;
}

Results

Alice Bob Charlie 
Alice Bob Charlie 
*ptr = 42

Example 4: Note copying vs referencing when using auto to iterate over containers

#include <iostream>
#include <vector>
#include <string>

int main()
{
    std::vector<std::string> names = {"Alice", "Bob", "Charlie"};

    // ❌ 错误用法:auto 会拷贝每个元素(低效)
    std::cout << "auto (copies): ";
    for (auto s : names)
    {
        s = "X";  // 修改的是拷贝,不影响原容器
    }
    for (auto s : names)
    {
        std::cout << s << " ";
    }
    std::cout << "(unchanged)\n";

    // ✅ 正确用法:auto& 修改原容器中的元素
    for (auto& s : names)
    {
        s = "X";
    }
    std::cout << "auto& (references): ";
    for (auto s : names)
    {
        std::cout << s << " ";
    }
    std::cout << "(modified)\n";

    return 0;
}

Results

auto (copies): Alice Bob Charlie (unchanged)
auto& (references): X X X (modified)

Example 5: The difference between auto return value and decltype(auto) in Example 4

#include <iostream>

int global_score = 80;

int& score_ref()
{
    return global_score;
}

// auto 作为函数返回类型时,会按"值"返回,引用会被丢掉
auto read_score()
{
    return score_ref();
}

// decltype(auto) 会保留 score_ref() 的 int& 返回类型
decltype(auto) borrow_score()
{
    return score_ref();
}

int main()
{
    auto a = score_ref();       // a 是 int,拷贝
    a = 90;
    std::cout << "after auto a = 90, global_score = " << global_score << "\n";

    auto& b = score_ref();      // b 是 int&,引用
    b = 90;
    std::cout << "after auto& b = 90, global_score = " << global_score << "\n";

    auto c = read_score();      // c 是 int,read_score 本身也返回拷贝
    c = 100;
    std::cout << "after auto c = 100, global_score = " << global_score << "\n";

    decltype(auto) d = borrow_score(); // d 是 int&,仍然引用 global_score
    d = 100;
    std::cout << "after decltype(auto) d = 100, global_score = " << global_score << "\n";

    return 0;
}

Results

after auto a = 90, global_score = 80
after auto& b = 90, global_score = 90
after auto c = 100, global_score = 90
after decltype(auto) d = 100, global_score = 100

runtime results

See the "running results" for each example above.

Key syntax explanation in the example

|Here is the translation of the provided Simplified Chinese Markdown fragment into natural American English, following all specified rules.


ExampleDiscusses whatNewly emerged syntaxWhy write it this wayPrecautions
Example 1Basic Type Deductionauto x = 表达式In the simplest case, the type is determined by the initialization value.String literal is inferred as const char*
Example 2auto vs auto& vs const auto&auto&const auto&auto will lose references and top-level const; you must use auto& to reference the original variable.Be careful when iterating through container elements.
Example 3Simplify complex typesUse auto with iterators and smart pointers当类型名过长时,可使用 auto 关键字保持代码的可读性。例如:
// 不推荐:冗长的类型声明
std::vector<std::pair<int, std::string>>::iterator it = myVector.begin();

// 推荐:使用 auto
auto it = myVector.begin();

这样不仅使代码更简洁,还能在类型变更时减少维护成本。|auto doesn't weaken type safety; it just helps the compiler write the code for you.| |Example 4|The copy trap of auto during iteration|Range-based for loops combined with auto or auto& in C++|Traverse and copy elements, auto& reference elements|To modify the original container, you must use auto&.| |Example 5|auto returns value vs decltype(auto)|auto function return, decltype(auto)|When a function returns a reference, a normal auto will degrade to a value return.|decltype(auto) is quite powerful, but also make sure it won't return a dangling reference.|

Common Errors

Error 1: Thought that auto could automatically infer as a reference.

int x = 10;
auto y = x;
y = 20;  // x 不会变!y 是拷贝不是引用

Correct approach: The original variable needs to be modified using auto&.

Error 2: Using auto to declare function parameters

void func(auto x) { ... }  // C++20 之前是错误!(除非是泛型 lambda)

Correct approach: ordinary function parameters cannot use auto (C++20 allows it, but that's template syntax).

Error 3: auto cannot be used in a multi-variable declaration

auto x = 1, y = 3.14;  // ❌ 编译错误!推导类型不一致

The correct approach: each auto variable is declared separately.

Error 4: Overusing 'auto' makes the business meaning disappear

auto timeout = 3000;  // 3000 是毫秒?秒?次数?

The correct approach: Types or names should convey meaning. For example, std::chrono::milliseconds timeout{3000};, or at least auto timeout_ms = 3000;.

使用建议

  • 明确目标:在开始前确定您的具体需求,以便选择最合适的工具或教程。
  • 充分利用资源:参考官方文档、教程和博客,这些资料能帮助您快速上手并解决问题。
  • 实践应用:通过动手操作项目或编写代码来巩固学习成果,提升实际操作能力。
  • 问题解决:遇到困难时,查阅参考资料或寻求社区支持,逐步培养独立解决问题的能力。
  • 分享经验:完成项目后,可以撰写文章或博客分享心得,帮助其他学习者。

如果需要针对特定领域(如单片机、机器人或环境搭建)的进一步建议,请提供更多信息,我将为您细化内容。

  1. Use auto wherever possible: reduce repetitive type declarations to make the code more concise.
  2. Iterate over containers using const auto& (without modification) or auto&** (needs modification), to avoid accidental copying.
  3. Places that clearly need references must include auto&: auto will not automatically infer references.
  4. auto cannot fully replace explicit types: When types are not obvious (such as inferring from a function's return value), writing types explicitly might be clearer.
  5. decltype(auto) should only be used when the reference truly needs to be preserved: it is more precise and makes it easier to expose dangling references.

Summary

  • auto allows compilers to automatically infer variable types, reducing the need for verbose type declarations.
  • auto loses references and top-level const; to traverse a container, use const auto& or auto&.
  • This is particularly suited for simplifying complex types such as iterators and smart pointers.
  • auto functions return by value by default; in order to preserve reference semantics, use decltype(auto).
  • auto is still strongly typed, and its type is determined at compile time.
音乐页