← 练习册目录

第 9 章 现代 C++ 特性

red wenzi · 2026-09-15 · 编程语言 · C++ · 练习册 · 10 题
📝 本章练习:10 题(A 识别 / B 理解 / C 改错 / D 写程序)。先自己做完再看答案——A、B 档不翻书做,C、D 档必须真的编译运行。

9.1 auto 与结构化绑定

A1识别判断题:auto 推导出的类型是确定的,只是不用你写出来。

答:______________

✅ 查看答案与解析

答案 对

解析:auto n = 42; 就是 int。它不是动态类型,是编译期推导。

A2识别判断题:nullptr 是类型安全的空指针,能区分“空指针”和“整数 0”。

答:______________

✅ 查看答案与解析

答案 对

解析:用 nullptr 而不是 NULL/0,重载解析不会出错。

B1理解选择题:for (const auto& [key, value] : m)(m 是 map)里发生了什么?

逐个复制整个 map

结构化绑定:把每个 pair 解包成 key 和 value 两个变量

编译错误

只遍历 key

答:______________

✅ 查看答案与解析

答案 B

解析:C++17 结构化绑定把 pair<const Key, Value> 解包成两个变量,const auto& 保证只读不拷贝。

C1应用改错题:下面滥用 auto,读代码的人看不出 x 是什么类型。
auto x = compute();   // 类型完全看不出来
✅ 查看答案与解析

答案 类型不明显时显式写出:

解析:auto 简化的是“明显但啰嗦”的类型(迭代器、长类型名);类型不明显时不要滥用。

double x = compute();
// 或者用明确的函数签名 / 给变量起能说明类型的名字
D1创造写程序:用 std::map 存三个城市的人口,用结构化绑定遍历输出“城市: 人口”。

提示:for (const auto& [city, pop] : m)。

✅ 查看答案与解析

答案 参考答案:

解析:结构化绑定让遍历 map 变得非常清爽。数据为示例演示用。

#include <iostream>
#include <map>
#include <string>
int main() {
    std::map<std::string, int> m{{"Jinan", 900}, {"Taiyuan", 530}, {"Shanghai", 2400}};
    for (const auto& [city, pop] : m) {
        std::cout << city << ": " << pop << '\n';
    }
    return 0;
}

9.2 constexpr 与异常

A1识别判断题:constexpr 的计算结果可以当数组长度、模板参数用。

答:______________

✅ 查看答案与解析

答案 对

解析:std::array<int, factorial(4)> 这种写法合法,因为 factorial(4) 在编译期就算出 24。

A2识别判断题:捕获异常应该按 const 引用(catch (const std::exception& e))。

答:______________

✅ 查看答案与解析

答案 对

解析:按值捕获会拷贝异常对象(可能切片);按 const 引用避免拷贝、保留多态信息。

B1理解选择题:static_assert(kFact5 == 120); 在什么时候检查?

运行时

编译期

链接期

从不在

答:______________

✅ 查看答案与解析

答案 B

解析:static_assert 是编译期断言,不满足直接编译失败。

C1应用改错题:下面想在编译期算阶乘,但写法导致编译错误。
constexpr int factorial(int n) {
    int result = 1;
    for (int i = 2; i <= n; ++i) { result *= i; }  // C++14 后合法,但若用旧标准/写法受限
    return result;
}
✅ 查看答案与解析

答案 C++14 起 constexpr 函数内允许循环。若必须兼容 C++11,用递归:

解析:递归版在任何标准下都能编译期求值;注意 constexpr 函数的调用参数也必须是编译期常量才能编译期算。

constexpr int factorial(int n) { return n <= 1 ? 1 : n * factorial(n - 1); }
D1创造写程序:写一个 divide(a, b),b == 0 时 throw std::invalid_argument,main 里 try-catch 捕获并输出错误信息。

提示:#include <stdexcept>;catch 用 const 引用。

✅ 查看答案与解析

答案 参考答案:

解析:异常按 const 引用捕获;RAII 写对的话,抛异常不会泄漏资源。

#include <iostream>
#include <stdexcept>
double divide(double a, double b) {
    if (b == 0.0) { throw std::invalid_argument("divide by zero"); }
    return a / b;
}
int main() {
    try {
        std::cout << divide(1.0, 0.0) << '\n';
    }
    catch (const std::invalid_argument& e) {
        std::cout << "caught: " << e.what() << '\n';
    }
    return 0;
}
// 输出:caught: divide by zero
📚 相关概念:编译与链接 · STL · map / set · 迭代器