库
标准库进阶:string、时间、随机、包装类型
String · chrono · random · optional/variant
这一章把第 10 章提到的几个现代库真正用起来。它们不性感,但每天都在用。看完你就明白:为什么现代 C++ 程序里几乎看不到 malloc 和 char 数组了。
std::string 的常用操作
拼接、查找、截取、转数字
#include <string>
#include <iostream>
std::string s = "hello";
s += " world"; // 拼接,变成 "hello world"
auto pos = s.find("world"); // 找子串,返回位置;找不到返回 npos
std::string sub = s.substr(0, 5); // 从 0 取 5 个字符:"hello"
int n = std::stoi("123"); // 字符串转 int;stod 转 double
std::string back = std::to_string(3.14); // 数字转回字符串
std::optional:可能没值
以前查不到就返回 -1 或空指针,调用者很容易忘判断。std::optional 把"有没有值"直接写进类型里。
用 optional 表示"可能查不到"
#include <optional>
#include <map>
// 查成绩:查到返回分数,查不到返回 std::nullopt
std::optional<double>
lookup(const std::map<std::string,double>& db, const std::string& name) {
auto it = db.find(name);
if (it == db.end()) return std::nullopt; // 没有值
return it->second;
}
// 调用者必须显式处理"没有"的情况
auto r = lookup(db, "小明");
if (r) std::cout << "成绩:" << *r; // 有值才解引用
else std::cout << "没这个人";
variant / any / tuple:能装多种类型
| 类型(C++17) | 大白话 |
|---|---|
variant<int,double> | 一个变量"是 int 或 是 double",但同一时刻只能是其中一种,类型安全。 |
any | 能装任意一种类型的盒子,取出时要指定类型。 |
tuple<int,string,double> | 打包多个不同类型的值,配合结构化绑定解包。 |
tuple + 结构化绑定
#include <tuple>
// 一个函数想同时返回三个值,用 tuple 打包
auto get_user() {
return std::make_tuple(std::string("小明"), 18, 92.5);
}
auto [name, age, score] = get_user(); // 一次解开三个值
时间与随机数
chrono 计时 + mt19937 真随机
#include <chrono>
#include <random>
// 计时:测一段代码跑了多久
auto t0 = std::chrono::steady_clock::now();
// ... 干点活 ...
auto t1 = std::chrono::steady_clock::now();
double ms = std::chrono::duration<double, std::milli>(t1 - t0).count();
// 随机数:mt19937 比老 rand() 均匀、可播种
std::mt19937 rng(std::random_device{}());
std::uniform_int_distribution<int> dice(1, 6);
int roll = dice(rng); // 掷骰子 1~6
构建工具:CMake
C++ 项目跨平台、依赖多,手写 Makefile 扛不住。CMake 是事实标准——写一份 CMakeLists.txt,它帮你生成 Makefile 或 VS 工程。最小骨架:
CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(MyApp CXX)
set(CMAKE_CXX_STANDARD 20) # 用 C++20
add_executable(app main.cpp task.cpp) # 把这些源文件编成 app
用法
$ cmake -B build # 生成构建文件
$ cmake --build build # 编译
$ ./build/app
学习资源(都能白嫖)
| 资源 | 特点 | 适合阶段 |
|---|---|---|
| cppreference.com | C++ 标准库权威手册,每个类都有例子,必备书签。 | 查 API,随手翻 |
| C++ Core Guidelines | C++ 之父本人牵头的编码规范,讲"为什么这么写"。 | 入门后精读 |
| Compiler Explorer(godbolt) | 实时看代码变汇编、看 RVO/移动怎么生效。 | 学移动语义时 |
| 《Effective Modern C++》 | Scott Meyers 写现代 C++ 的 42 条军规,经典。 | 有基础后进阶 |
五个最常用设计模式:会这几个就够日常
设计模式不是八股,是"别人踩过坑总结出的沟通语言"。C++ 面试和工程里出现频率最高的五个,挨个说人话:
| 模式 | 解决什么问题(人话) |
|---|---|
| 单例 Singleton | 全程序只有一个实例(配置对象、日志器)。懒汉式 + 互斥锁线程安全。注意:现代 C++ 也常用"命名空间里的全局函数 + 局部静态变量"代替。 |
| 工厂 Factory | new 一个对象时不想写死具体类。给一个参数,工厂返回"该类型的对象",方便以后加新品种不改调用方。 |
| 观察者 Observer | "发布-订阅":一放多。被观察的数据变了,所有订阅者自动收到通知。Qt 的 signal/slot、事件回调都是它。 |
| 策略 Strategy | 同一类行为有多种算法可换(排序策略、打折方式)。把算法抽成可替换对象,运行时切换。STL 算法传入不同 lambda 就是策略思想。 |
| 装饰器 Decorator | 不修改原类,用"层层包装"给对象加功能(咖啡加奶加糖)。C++ 的 std::shared_ptr 包装原始指针、IO 流套 stream 就是装饰器。 |
单例(Meyers' Singleton,C++11 起线程安全)最常用写法
class Config {
public:
static Config& instance() {
static Config inst; // 局部静态变量:第一次调用时构造,C++11 保证线程安全
return inst;
}
// 禁止拷贝和赋值,保证只有一个
Config(const Config&) = delete;
Config& operator=(const Config&) = delete;
private:
Config() = default; // 构造私有,外面 new 不了
};
// 用法:Config::instance().load("app.cfg");
建议:别为了用模式而用模式。先写直白代码,当发现"这里改来改去""要插新分支"时,再回头套对应模式——模式是给"变化点"做隔离的,不是默认框架。