简介

  • 所有标准库类和函数都在std名称空间或其子名称空间中声明
  • C++标准库的核心是泛型容器和泛型算法。该库中的这个子集通常程序标准模板库(Standard Template Library, STL),因为它最初基于第三方库“标准模板库”,该库大量使用了模板。

<string> – 字符串 [ok]

  • C++20包括了一个强大的类型安全的字符串格式化库,可以通过定义在<format>头文件中的std::format()进行访问

<regex> – 正则表达式[ok]

<fstream> – I/O流[ok]

  • 大多数的I/O功能在如下几个头文件中定义:
    • <fstream>
    • <iomanip>
    • <ios>
    • <iosfwd>
    • <iostream>
    • <istream>
    • <ostream>
    • <sstream>
    • <streambuf>
    • <strstream>

<iomanip>

resetiosflags()

  • 简述:清除指定的 ios_base 标志

setiosflags()

  • 简述:设置指定的 ios_base 标志

setbase()

  • 简述:更改用于整数 I/O 的基数

setfill()

  • 简述:更改填充字符

setprecision()

  • 简述:更改浮点精度

setw()

  • 简述:更改下个输入/输出域的宽度

get_money()

  • 简述:剖析货币值

put_money()

  • 简述:格式化并输出货币值

get_time()

  • 简述:剖析指定格式的日期/时间值

put_time()

  • 简述:按照指定格式格式化并输出日期/时间值
  • 声明:template<class CharT> put_time(const std::tm* tmb, const CharT* fmt);
  • 参数:
    • tmb – 指向从 std::localtime 或 std::gmtime 获得的日历时间结构体的指针
    • fmt – 指向指定转换格式的空终止 CharT 串的指针,具体参考:https://zh.cppreference.com/w/cpp/io/manip/put_time(默认使用%c %Z

quoted()

  • 简述:插入和读取带有内嵌空格的被引号括起来的字符串

<memory> – 智能指针[ok]

  • 编写健壮程序时,需要面对的一个问题就是要知道何时删除对象。
  • 有几种可能发生的故障:
    • 根本没有删除对象(没有释放内存),这称为内存泄漏(memory leaks)。
    • 一段代码删除了内存,而另一段代码仍然引用了这个内存,导致直线那个内存的指针不再可用或已重新分配作他用,这称为悬空指针(dangling pointer)
    • 一段代码释放了内存,而另一端代码试图释放同一块内存,这称为双重释放(double deletion)

<exception> – 异常[ok]

  • 大多数异常支持在下面几个头文件中定义:
    • <exception>
    • <stdexcept>
    • <system_error>

<cmath> – 数学工具

  • 数学工具类和函数

<chrono> – 时间和日期工具[ok]

  • 简述:在C++11的日期时间库中,共有3个概念,分别是持续时间(Duration)、时间点(timepoint)、时钟(clock)。

Clocks

  • 定义中的时钟主要有3个,分别是:
    • system_clock,顾名思义,就是系统时钟,他一般是unix时间,即从1970年1月1日到现在的间隔。如果系统时间发生调整,那么调用该方法获取的时间值也会跟着变化。
    • steady_clock,是单调时间,即每后一次调用都一定会比前一次调用的时间要晚,它并不反映真实的世界时间。在内部的实现中,有可能是系统开启以来的时间。通过该时钟很适合用来获取一段时间内的间隔,它不随系统时间改变而改变
    • high_resolution_clock,高精度时间,用来测量细微间隔的一段时间,它的内部实现中可能是system_clock或是steady_clock,也可能是其他独立的时间。
  • 一般来说,我们使用的都是system_clock
  • system_clock的主要方法有3个,分别是
    • now,用来获取当前时间。
    • to_time_t,用来将系统时间转变为std::time_t类型。
    • from_time_t,用来将std::time_t类型转换为系统时间点
  • 使用system_clock获取当前系统时间。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
      #include <iostream>
      #include <chrono>
      int main() {    
          auto time = std::chrono::system_clock::now();
          auto tt = std::chrono::system_clock::to_time_t(time);
          std::cout << std::put_time(std::localtime(&tt), "%Y-%m-%d %H:%M:%S") << std::endl;
            
          return 0;
      }
    
  • 统计函数的执行耗时,这种情况更适合使用steady_clock。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    
      #include <iostream>
      #include <chrono>
    
      long fibonacci(unsigned n)
      {
          if (n < 2) return n;
          return fibonacci(n - 1) + fibonacci(n - 2);
      }
    
      int main()
      {
          auto start = std::chrono::steady_clock::now();
          std::cout << "f(42) = " << fibonacci(42) << '\n';
          auto end = std::chrono::steady_clock::now();
          std::chrono::duration<double> elapsed_seconds = end-start;
          std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n";
      }
    

Duration

  • 持续时间表示一个时间段,比如1s、1min、1day等等,这些时间段是有单位的,因此持续时间也是一个模板变量,用来指定不同的单位
  • 它的定义如下:
    1
    2
    3
    
      // Rep表示单位的数量单位
      // Period表示单位
      template<class Rep,  class Period = std::ratio<1>> class duration;
    
  • Period用来表示时间的单位,比如秒、天、小时等等,而Rep则表示容纳某个数量时间的单位。比较绕口,举个例子,比如说10天,那么Period是单位day,那么其数量是10,而10的类型可以是int型,也可以short型,Rep就用来表示这到底是什么类型存储这个量,如果类型过小,如果时间太长的话将会导致溢出。
  • 再来看下Period的定义,
    1
    2
    3
    
      // Num,表示分子
      // Denom,表示分母
      template<std::intmax_t Num, std::intmax_t Denom = 1> class ratio;
    
  • 举个简单点的例子,Num为1,Denom也为1时,表示是1s,如果Num为1,Denom为1000,那么相当于是1/1000s,也即毫秒。如果Num为60,Denom为1,那么表示 60 / 1s,也即相当于1min。
  • 下面是chrono头文件中的一些常见持续时间定义。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
      Type	Definition
      std::chrono::nanoseconds	duration</*signed integer type of at least 64 bits*/, std::nano>
      std::chrono::microseconds	duration</*signed integer type of at least 55 bits*/, std::micro>
      std::chrono::milliseconds	duration</*signed integer type of at least 45 bits*/, std::milli>
      std::chrono::seconds	duration</*signed integer type of at least 35 bits*/>
      std::chrono::minutes	duration</*signed integer type of at least 29 bits*/, std::ratio<60>>
      std::chrono::hours	duration</*signed integer type of at least 23 bits*/, std::ratio<3600>>
      std::chrono::days (since C++20)	duration</*signed integer type of at least 25 bits*/, std::ratio<86400>>
      std::chrono::weeks (since C++20)	duration</*signed integer type of at least 22 bits*/, std::ratio<604800>>
      std::chrono::months (since C++20)	duration</*signed integer type of at least 20 bits*/, std::ratio<2629746>>
      std::chrono::years (since C++20)	duration</*signed integer type of at least 17 bits*/, std::ratio<31556952>>
    
  • 针对Duraion来说,一般有两种操作,
    • 时间的增减。
    • 不同持续时间单位之间的转换。
  • Duration重载了+/-运算符,可以直接进行+/-操作,类型之间的转换可以使用duration_cast方法。
  • 下面是一些使用实例。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    
      #include <iostream>
      #include <chrono>
    
      int main() {
          std::chrono::milliseconds ms(3);
          printf("%lld\n", ms.count());
    
          using second = std::chrono::duration<double>;
          auto s = std::chrono::duration_cast<second>(ms);
          printf("%llf\n", s.count());
    
          std::chrono::seconds sec(10);
          auto du = sec + ms;
          printf("%lld\n", du.count());
    
          return 0;
      }
    

TimePoint

  • 从时钟拿到的时间是时间点,它代表了时间段上的一个点,比如2019年10月21日10:20:10。
  • 时间点的定义如下。
    • template<class Clock, class Duration = typename Clock::duration> class time_point;
  • 通过time_point的模板参数,我们可以看到,一个是时钟,另外一个是持续时间,实际上timepoint就是一个时钟的基准时间加上一个时间段
  • 对于时间点来说,下面这几个方法比较重要。
    • time_since_epoch,获取以模板时钟的起始时间到现在的这个持续时间
    • time_point_cast,用来将时间点转换为基于同一个时钟,但不同类型持续时间的时间点。
    • 时间点也重载了+/-运算符,用来进行两个时间点之间的相加减
  • 下面是一些使用示例。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
      #include <iostream>
      #include <chrono>
    
      int main() {
          std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
          std::chrono::minutes m(20);
          std::chrono::time_point<std::chrono::system_clock> then = now + m;
          std::time_t tt = std::chrono::system_clock::to_time_t(then);
          std::cout << "timestamp is : " << now.time_since_epoch().count() << std::endl;
          std::cout << std::put_time(std::localtime(&tt), "%F %T") << std::endl;
    
          // 降低时间精度,默认system_clock的duration精度是 1/10 micro sec
          auto then_min = std::chrono::time_point_cast<std::chrono::minutes>(then);
          tt = std::chrono::system_clock::to_time_t(then_min);
          std::cout << std::put_time(std::localtime(&tt), "%F %T") << std::endl;
    
          return 0;
      }
    

一些应用

  • 获取时间戳。
    1
    2
    3
    4
    5
    6
    7
    8
    
      std::time_t getTimeStamp()
      {
          std::chrono::time_point<std::chrono::system_clock,std::chrono::milliseconds> tp = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
          auto tmp=std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch());
          std::time_t timestamp = tmp.count();
          //std::time_t timestamp = std::chrono::system_clock::to_time_t(tp);
          return timestamp;
      }
    
  • 将时间戳转为日期。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
      std::tm* gettm(int64 timestamp)
      {
          int64 milli = timestamp+ (int64)8*60*60*1000;//此处转化为东八区北京时间,如果是其它时区需要按需求修改
          auto mTime = std::chrono::milliseconds(milli);
          auto tp=std::chrono::time_point<std::chrono::system_clock,std::chrono::milliseconds>(mTime);
          auto tt = std::chrono::system_clock::to_time_t(tp);
          std::tm* now = std::gmtime(&tt);
          printf("%4d年%02d月%02d日 %02d:%02d:%02d\n",now->tm_year+1900,now->tm_mon+1,now->tm_mday,now->tm_hour,now->tm_min,now->tm_sec);
         return now;
      }
    
  • 在上面的程序中,时间精度只到秒,这是time_t结构的限制,如果希望获取到ms精度,那么直接使用timestamp % 1000的方式就行。

<random> – 随机数[ok]

  • 随机数库,带有随机数引擎,随机数引擎适配器以及随机数分布。
  • 通过这些组件可以生成更适合特定问题的随机数,例如正态分布,负指数分布等

<initializer_list> – 初始化列表

  • 它们便于编写参数数目可变的函数

<utility> – pair

  • 它定义了pair类模板,用于存储两种不同类型的元素。这称为存储异构元素
  • pair允许在一个对象中保存类型毫不相关的元素

<tuple> – tuple

  • 它定义的tuple是pair的一种泛化,它是固定大小的序列,元组的元素可以是异构的,tuple实例化的元素数目和类型在编译器是固定不变的。

词汇类型(vocabulary type)

  • <optional>
    • 要么存储指定类型的值,要么什么都不存储
  • <variant>
    • 可存储单个值(属于一组给定类型中的一种类型)
  • <any>
    • 可包含单个值,值可以是任何类型

<functional> – 函数对象

  • <functional>中定义的std::function函数模板是一个多态函数包装器,可以用来创建指向任何可调用对象的类型,例如函数,函数对象或者lambda表达式
  • std::function的示例可以用作函数指针,也可以用作函数实现回调的参数,可以存储,赋值,移动,也可以执行

  • 函数模板的模板参数看起来和大多数模板参数有些不同,语法如下:
    • std::function<R(ArgTypes...)>
  • 详解:
    • R : 是函数的返回类型
    • ArgTypes : 是函数参数类型的逗号分隔列表
  • 实现函数调用运算符的类称为函数对象(function object)
  • 函数对象可用作某些标准库算法的谓词

<filesystem> – 文件系统

<thread> – 多线程[ok]

<type_traits> – 类型萃取

<cstdint> – 标准整数类型

  • 它定义了大量标准整数类型,例如int8_t 和 int64_t 等,还包含了多个宏(指定这些类型的最小值和最大值)

<version> – 相关实现信息[ok]

  • 它可用于查询正在使用的C++标准库的相关实现信息
    • 版本号
    • 发布日期
    • 版权声明

<source_location> – 源位置

  • C++20添加了std::source_location类,用来查询有关源代码的信息,例如文件名,函数名,行号和列号,并可用于替换旧的C风格宏__FILE____LINE__

容器

<vector>[ok]

<list>

<forward_list>

<deque>

<array>

<span>

<queue>

<stack>

<set>

<map>

<alogrithm> – 算法[ok]

<ranges> – 范围库

  • C++20引入了范围库,这使得处理元素序列变得更加简单和优雅