C++实战其他两篇文章:
C++实战 概述 |代码风格
C++ 实战 语言特性
using string = std::basic_string<char>; // string其实是一个类型别名
//是模板类 basic_string 的特化形式,是一个 typedef:
Unicode它的目标是用一种编码方式统一处理人类语言 文字,使用 32 位(4 个字节)来保证能够容纳过去或者将来所有的文字。//char 类型,无法支持 Unicode
using wstring = std::basic_string<wchar_t>;
using u16string = std::basic_string<char16_t>; //适配 UTF-16
using u32string = std::basic_string<char32_t>; //适配 UTF-32
+Unicode 还有一个 UTF-8 编码方式,与单字节的 char 完全兼容
基本使用:


C++11 还为字面量增加了一个“原始字符串”(Raw string literal)的新表示形式。这样就没必要使用\ 对不可打印字符进行转义了
// 如果想输出()
auto str5 = R"==(R"(xxx)")==";// 原样输出:R"(xxx)"


C++ 正则表达式主要有两个类。
regex:表示一个正则表达式,是 basic_regex 的特化形式;
smatch:表示正则表达式的匹配结果,是 match_results 的特化形式。
C++ 正则匹配有三个算法,注意它们都是“只读”的,不会变动原字符串。
regex_match():完全匹配一个字符串;
regex_search():在字符串里查找一个正则匹配;
regex_replace():正则查找再做替换。

你只要用 regex 定义好一个表达式,然后再调用匹配算法,就可以立刻得到结果, 用起来和其他语言差不多。不过,在写正则的时候,记得最好要用“原始字符串”,不然转义符会特别的麻烦。
regex_match() 检查字符串,函数会返回 bool 值表示是否完全匹配 正则。如果匹配成功,结果存储在 what 里,可以像容器那样去访问,第 0 号元素是整个 匹配串,其他的是子表达式匹配串:



尽量不要反复创建正则对象,能重用就重用。 在使用循环的时候更要特别注意,一定要把正则提到循环体外。
regex_replace() 不需要匹配结果,而是要提供一个替换字符串,因为算法是“只读”的, 所以它会返回修改后的新字符串。
https://github.com/chronolaw/cpp_study/blob/master/section3/string.cpp
容器,就是能够“容纳”“存放”元素的一些数据结构。 容器 == 数据结构
容器,它也是 C++ 泛型编程范式的基础。







key 具备两个条件: 一是可以计算 hash 值,二是能够执行相等比较操作。



vector 是动态的, 不要使用new / delete
算法是 STL(标准库前身)的三大要件之一(容器、算法、迭代器),也是 C++ 标准 库里一个非常重要的部分,但它却没有像容器那样被大众广泛接受。
C++ 里的算法,指的是工作在容器上的一些泛型函数,会对容器内的元素实施的各种操作。for 或者 while,通 过循环遍历来逐个处理容器里的元素,比如说 count 算法,它的功能非常简单,就是统计某个元素的出现次数,完全可以用 range-for 来实现同样的功能。

C++ 里的迭代器也有很多种,比如输入迭代器、输出迭代器、双向迭代器、随机访问迭代 ,可以把它简单地理解为另一种形式的“智能指针”,只是它强调的是对数据的访问,而不是生命周期管理。


for_each 算法的价值就体现在这里,它把要做的事情分成了两部分,也就是两个函数:一个遍历容器元素,另一个操纵容器元素,而且名字的含义更明确,代码也有更好的封装。它能够促使我们更多地以“函数式编程”来思考,使用 lambda 来封装逻辑,得到更干净、更安全的代码。







C++ 多线程编程里读取 const 变量总是安全的,对类调用 const 成员函数、对 容器调用只读算法也总是线程安全的。 once_flag 类型的变量,最好是静态、全局的.static std::once_flag flag; // 全局的初始化标志
然后调用专门的 call_once() 函数
auto f = []()
{
std::call_once(flag, [](){
// 仅一次调用,注意要传flag // 匿名lambda,初始化函数,只会执行一次
// 在线程里运行的lambda表达式
cout << "only once" << endl; } );
};
thread t1(f);
thread t2(f);
// 启动两个线程,运行函数f

10 和 20,互不干扰 。static 就会输出 30

call_once、thread_local 和 atomic 这三个用于 C++ 多线程变成的工具,尽量消除显式地使用线程。
线程 : C++ 标准库里有专门的线程类thread,使用它就可以简单地创建线程,在名字空间 std::this_thread 里,还有 yield()、get_id()、sleep_for()、sleep_until() 等几个方便的管理函数。
原子操作atomic 结合 thread:

async(),它的含义是“异步运行”一个任务。

async() 会返回一个 future 变量,可以认为是代表了执行结果的“期货”,如果任务有返回值,就可以用成员函数 get() 获取。不过要特别注意,get() 只能调一次,再次获取结果会发生错误,抛出异常 std::future_error。(至于为什么这么设计我也不太清楚,没找到官方的解释)
另外,这里还有一个很隐蔽的“坑”,如果你不显式获取 async() 的返回值(即 future 对象),它就会同步阻塞直至任务完成(由于临时对象的析构函数),于是“async”就变成 了“sync”。所以,即使我们不关心返回值,也总要用 auto 来配合 async(),避免同步阻塞,就像下面 的示例代码那样


