题目

编写程序,演示 C++17 引入的核心实用工具类 std::optional<T>。告别传统 C 语言使用特殊魔法数字(如返回 -1、0 或 nullptr)代表查找失败的脆弱做法;设计一个安全的字典配置解析器,函数在命中时返回有效包装值,未命中时返回 std::nullopt;展示使用 has_value() 判定、value() 安全提取(空值时抛出 std::bad_optional_access)与 value_or(defaultVal) 提供保底默认值的现代优雅姿势。

输入格式:无需外部输入。

输出格式:输出有值读取、保底默认值降级与空值异常捕获测试。

数据范围与约定:C++17 std::optional、零堆开销值语义与空值类型安全。

思路与算法

1. 魔法数字的灾难
若查找温度函数返回 -1 表示失败,但 -1°C 恰好是一个完全合法的真实温度!使用 std::optional<double> 彻底将“是否成功”与“具体数值”解耦。

2. 零堆内存开销
std::optional<T> 内部是 bool has_value_ 加上一块足够容纳 T 的未初始化栈内存对齐缓冲区(aligned_storage),绝对无需发生任何动态堆分配。

3. value_or 的防御魅力
opt.value_or("default.conf") 可以在单行表达式内实现“有值则取值,无值则走安全降级默认值”,极大地精简了业务分支代码。

完整程序

#include <iostream>
#include <optional>
#include <string>
#include <unordered_map>

// 安全的配置项检索函数:返回 optional 包装器
std::optional<int> findServerPort(const std::string& serverName) {
    static const std::unordered_map<std::string, int> registry = {
        {"auth-service", 8081},
        {"payment-gateway", 8082},
        {"order-dispatcher", 8083}
    };

    auto it = registry.find(serverName);
    if (it != registry.end()) {
        return it->second; // 自动隐式包装为 std::optional<int>(it->second)
    }
    return std::nullopt;   // 明确返回无值状态,杜绝魔法数字
}

int main() {
    // 1. 成功命中的服务端口查询
    auto port1 = findServerPort("auth-service");
    if (port1.has_value()) {
        std::cout << "auth-service 注册端口: " << port1.value() << "\n";
    }

    // 2. 未命中的服务端口查询:使用 value_or 优雅保底降级
    auto port2 = findServerPort("unknown-service");
    int actualPort = port2.value_or(80); // 无值时安全退化为默认 80 端口
    std::cout << "unknown-service 解析端口 (带保底): " << actualPort 
              << " (原始是否配置: " << std::boolalpha << port2.has_value() << ")\n\n";

    // 3. 空值强取 value() 触发标准异常
    std::cout << "--- 测试无值时调用 .value() 异常拦截 ---\n";
    try {
        int val = port2.value(); // 抛出异常
        std::cout << "不可达输出: " << val << "\n";
    } catch (const std::bad_optional_access& e) {
        std::cout << "【安全捕获】拦截 std::bad_optional_access\n";
        (void)e;
    }

    return 0;
}

运行示例

输出:

auth-service 注册端口: 8081
unknown-service 解析端口 (带保底): 80 (原始是否配置: false)

--- 测试无值时调用 .value() 异常拦截 ---
【安全捕获】拦截 std::bad_optional_access