在 C++17 引入的 std::filesystem 库中,文件和目录的增删改查(CRUD)操作变得极其简单且跨平台。不再需要依赖底层的 POSIX API(如 open, stat, unlink)或 Windows API(CreateFile, DeleteFile),而是使用统一的 C++ 接口。
1. 创建与复制在 C++17 std::filesystem 中,文件的增操作主要涉及文件/目录的创建、复制以及内容的写入。由于 C++ 文件系统库主要关注路径和元数据的管理,创建文件内容通常仍然依赖传统的fstream库,而创建目录结构则是 filesystem 的强项。
1.1 创建创建操作主要分为:创建空目录、创建目录树(多级目录)、以及创建空文件。
创建目录
1bool create_directory(const std::filesystem::path& p);
功能:尝试创建一个由路径 p 指定的目录,如果父目录不存在,则会抛出异常。
返回值:
如果目录创建成功,或者目录已经存在,返回 true。
如果创建失败(例如父目录不存在,或者路 ...
1. 命名空间与路径在 C++17 之前,C++ 程序员处理文件和目录是一件非常痛苦的事情。
在 Windows 上,我们要用 CreateFile, FindFirstFile, ... 等乱七八糟的 API。
在 Linux/macOS 上,我们要用 POSIX 的 open, stat, opendir, readdir 等系统调用。
为了跨平台,我们可能还得依赖 Boost.Filesystem 这样庞大的第三方库。
好消息是 C++17 终于把文件系统操作标准化了!它被称为 std::filesystem(一般缩写为 fs)。它不仅能跨平台,而且类型安全、接口现代、异常清晰。
std::filesystem 位于头文件 <filesystem> 中。为了偷懒,我们通常定义一个别名 fs。
1234#include <filesystem>// 为了少打字,大家习惯用 namespace fsnamespace fs = std::filesystem;
C++17 引入的 std::filesystem 库(简称 fs)是现代 C++ 处理文件操 ...
1. 搜索器概述在 C++17 之前,如果我们想在一个字符串中查找子串,通常使用 std::string::find。虽然它很简单,但有几个明显的局限性:
算法单一:C++ 标准库只提供了简单的朴素算法(逐个字符比较)。
无法指定算法:如果你想用更高效的算法(如 KMP 或 Boyer-Moore),必须自己实现或寻找第三方库。
无法用于容器:find 是 std::string 的成员函数,不能直接用于 std::vector<char> 或其他容器。
接口不统一:字符串查找和泛型算法(如 std::search)的接口不一致。
C++17 引入了搜索器概念。它允许我们把 搜索算法 和 搜索操作 分离开来。现在,标准库里直接提供了Boyer-Moore 和 Boyer-Moore-Horspool 这两个高性能算法!
C++17 在 <functional> 头文件里引入了三种搜索器,每种都基于不同的算法:
std::default_searcher:
算法:就是标准库原来用的那种朴素算法。
用途:默认选项,短字符串用它足够了。
std::boyer ...
1. 读写分离在多线程编程中,数据的并发访问通常分为两类场景:
写-写互斥:多个线程同时修改数据会导致冲突,必须串行化。
读-读并发:多个线程同时读取数据通常是安全的,不需要互斥。
C++11 提供了 std::mutex,它是一个独占锁。即使在只读场景下,同一时间也只允许一个线程访问数据。这在读多写少的场景下会严重限制性能。
C++14 引入了一种读写锁std::shared_timed_mutex,也被称为共享独占互斥量。它允许多个线程同时读共享数据,但写数据时必须独占访问。相比普通的 std::mutex,它在读多写少的场景下能显著提高性能。此外,它支持超时机制,即可以设定等待锁的最长时间。
C++17 引入了 std::shared_mutex,这也是一种读写锁,主要目的是为了瘦身和高性能。大多数情况下,我们不需要超时功能(超时逻辑非常复杂且容易出错)。std::shared_mutex 去掉了时间相关的接口,实现上通常比 std::shared_timed_mutex 更轻量,占用内存更少,速度更快。
和std::shared_timed_mutex 一样,std::sh ...
1. std::shared_ptr<T[]>在 C++ 的世界里,手动管理内存(new 和 delete)是噩梦的开始。忘了 delete 会导致内存泄漏(程序越跑越慢),重复 delete 会导致程序崩溃。
std::shared_ptr 是 C++11 引入的救世主,到了 C++17,它变得更加成熟。可以把 shared_ptr 想象为一个拿着绳子(指针)拽着气球(堆内存对象)的人。
引用计数:气球上挂了一个标签,写着 “几根绳子拴着我”。
赋值/拷贝:相当于多接了一根绳子,计数 +1。
重置/销毁:相当于解开一根绳子,计数 -1。
释放:当最后一根绳子解开,气球飞走(自动执行 delete,内存被释放)。
在创建std::shared_ptr的时候,永远优先使用 std::make_shared,不要直接用 new。
1234567891011121314151617181920#include <memory>#include <iostream>class Widget {public: Widge ...
1. 为什么我们需要新的转换在 C++17 之前,C++ 程序员在处理字符和数字转换时经常面临两个痛苦的选择:
C 语言风格函数 (atoi, strtol, sprintf):
类型不安全(容易崩溃),不支持 std::string,功能受限,无法区分错误(比如输入 123abc 会被当成 123 处理)。
C++ 流 (std::stringstream/std::to_string):
std::stringstream - 极其慢(涉及内存分配、状态设置),代码冗长(写一行转换要三五行代码),不仅影响性能,还容易写错。
std::to_string - 可能抛出bad_alloc异常,并且无法控制精度、格式等
C++17 引入了 <charconv> 头文件,提供了一组全新的函数( std::to_chars 和 std::from_chars)。这些函数不仅速度极快(被认为是目前通用 C++ 库中最快的),而且极其方便(不分配内存,不抛异常)。
123456789101112131415161718#include <sstre ...
1. 什么是并行算法在 C++17 之前,当我们使用标准库算法(如 std::sort, std::accumulate)时,程序是串行执行的。
想象一下我们要洗一盆子的脏衣服:
串行执行:一件一件地洗,洗完第一件再洗第二件。即使有十个空闲的水槽,也只用了一个。
并行执行:有五个朋友(CPU 核心),大家一人抓几件衣服同时洗,速度自然快得多。
以前,如果想利用多核加速排序或遍历,必须手动写复杂的线程代码,不仅难写,还容易出错。C++17 为几乎所有的标准算法(约 70 个)引入了执行策略参数。现在,只需要在调用算法时多加一个参数,编译器和标准库就会自动利用多核 CPU 来帮我们加速计算,完全不需要自己写线程代码。
要使用并行算法,需要包含头文件:
1234#include <algorithm> // 算法头文件#include <execution> // 并行执行策略头文件// 执行策略位于std::execution命名空间using namespace std::execution;
C++17 定义了三种主要的执行策略,执行策略是一个 ...
1. std::byte 是什么?在 C++17 之前,当我们需要处理“字节”级别的数据(例如网络协议、文件二进制流、硬件寄存器)时,我们通常只有两个选择,但它们都有缺陷:
使用 char 或 unsigned char:
缺陷:char 太聪明了。它是字符类型,不仅代表数值,还代表 ASCII 码。
坑点:std::cout << my_char 会打印出字符 A 而不是数值 65。如果想把它当成纯二进制数据用,很容易和文本处理混淆。
使用 uint8_t(unsigned char 的别名来自头文件 <cstdint>):
缺陷:它是一个整数类型。
坑点:编译器和 IDE 会认为它是数字,允许你进行加减乘除 uint8_t a = 10; a = a + 5;。这在处理二进制位时往往会导致逻辑错误(我们通常只做位操作,很少把字节当数字加减)。
C++17 的解决方案是引入一个新的类型 std::byte用于在类型系统中明确表示字节数据。它不是字符,也不是整数,只是一个纯粹的字节表示。
它不是字符(不会打印出乱码)。
它不是整数(不能直接加减乘除 ...
1. std::as_const 概述在 C++ 编程中,我们经常需要重载成员函数,分别提供 const 版本和非 const 版本,以便在对象是只读(const)或可变(non-const)时采取不同的行为。最经典的例子是容器类中的下标运算符 operator[]:
123456789101112131415161718class MyVector {public: // 非 const 版本:用于读写 int& operator[](size_t index) { return data[index]; } // const 版本:用于只读 const int& operator[](size_t index) const { return data[index]; }private: std::vector<int> data;};
为了让代码更加简洁,开发者通常希望 非 const 版本的函数能够直接调用 ...
1. std::string_view 的登场在 C++17 之前,当我们需要编写一个函数来处理字符串时,通常会面临一个艰难的选择:
使用 const std::string&
优点:安全,避免拷贝。
缺点:如果参数是一个字符串字面量(如 "hello")或者是一个 C 风格字符串(如 char*),编译器必须隐式地创建一个临时的 std::string 对象。这意味着会发生内存分配,这是非常昂贵的操作!
使用 const char*
优点:速度快,没有内存分配,可以接受字面量。
缺点:不安全,不能获取字符串长度(必须调用 strlen),不能直接使用 STL 算法,一旦涉及到 std::string 成员就麻烦了。
std::string_view 是 C++17 引入的一个只读引用包装器。我们可以把它想象成指向字符串的窗户:它只负责观察字符串的数据,而不拥有字符串的数据。
std::string_view 类 API 在线查询
std::string_view 的构造函数设计得非常宽容,下面这些类型都可以隐式转换为 string_view: ...









































