转载请说明出处 http://www.cnblogs.com/eagledai/
看到这个视频之前,一直没有觉得 C++11 <chrono> 库有什么用,而且觉得有些怪异。看过之后,为这个库的精巧所折服。设计的实在是太巧妙了!
视频地址:https://www.youtube.com/watch?v=P32hvk8b13M&t=203s
What to talk:
- Motivation
- Time durations
- Points in time
- Clocks
- Exmaples
Motivation 动机
希望能有这样的代码,代码更可读.
sleep(10ms);//This needs C++14, rather then C++11
利用算术类型来表示一段时间(duration),或者时间点(time point),这种方式本质上都很难清晰准确。所以,<chrono>库设计成,帮助编译器在编译时间就找到逻辑错误。手段:通过生成distince concepts, distinct types.
Time Durations
如何构造:
更多用法:
加法/减法
比较操作符
void f(seconds d)
{
cout << d.count() << "s\n";
}
f(3s - 2s);
output: 1s
注意:下面替换成毫秒:
void f(milliseconds d)
{
cout << d.count() << "ms\n";
}
f(3s - 2s); // output: 1000ms,并且compile time就能转换,不会带来执行时的开销
f(3ms - ms); // output: 1ms
f(3s - 2ms); // output: 2998ms
f(3); // compile error
17:50 关于秒与毫秒的转换
<chrono>自动进行秒和毫秒之间的转换,并且不会带来性能损失。手动转换很容易出错,应该避免。
只要编译能过,就是工作的!如果编译不过,一定要弄清楚,肯定有地方写错了!
22:06 关于秒与毫秒的转换
如果转换会带来精度损失,编译就会报错。如果一定需要这样的转换,explicitly的转换
23:05 更多的truncate转换
除了seconds,milliseconds,还有更多,并且都可以像seconds,milliseconds一样互相转换。
如果觉得64bit表示seconds太浪费,<chrono>还提供下面的方法,依然可以像上面的那些duration那样互转。
using seconds32 = std::chrono::duration<int32_t>;
甚至下面这个也能工作:
using seconds32 = std::chrono::duration<uint32_t>;
甚至下面这个也能工作(使用“safeint”库):
using seconds32 = std::chrono::duration<safe<uint32_t>>;
甚至下面这个也能工作(使用浮点类型):
using fseconds = std::chrono::duration<float>;
如果我想定义自己毫秒呢?std::milli实际上是一个预定义的ratio
using my_ms = std::chrono::duration<double, std::milli>;
void f(my_ms d)
{
cout << d.count() << " ms\n";
}
f(45ms + 63us); // 45.063 ms
30:17 预定义的类型是怎么定义的?
31:15 ratio长什么样?
ratio是编译时分数(不在运行时计算),两个模板参数,一个是分子,一个分母
33:00 实际上类duration只有一个成员,就是Rep,一般是long long
所以开头所说的seconds类,其实是一个lie,真实的实现是duration的一个特化
甚至用户可以自定义duration。例如,一帧1/60秒
using frames = std::chrono::duration<int32_t, std::ratio<1, 60>>;
这个frames也可以和上面那些标准提供的durations类型一起无缝互操作。
39:33 总结
这个库主要进行类型转换。
- 如果转换是无损的,隐式转换
- 如果转换是有损的,需要duration_cast
- 如果转换是危险的,需要特殊的显示的方法
所以,尽量使用implicit转换,只有在确实需要truncation的时候使用duration_cast,尽量别使用.count()
Points in time (41:29)
第一个模板参数Clock后面会有,第二个是duraion,默认类型是Clock的duration。只有duration被保存。Clock是没被保存的。
time_point和duration内部用同样的结构表示,但是完全不同的概念。
time_points 相减得到 duration
time_point 加或者减 duration 得到 time_point
time_point 不能相加
这些都是编译时自动检查的。
time_point 的转换和 duration 的转换很类似。
就像 duration_cast 一样,time_point_cast 也能从精度高的向精度低的转换。
Clocks (46:14)
is_steady
- true: 不能被调整
- false: 可以被调整。例如网络时钟,闰秒调整
所有的 time_point 都和一个 clock 关联
不同的 clock 的 time_point 是不能转换的
这样的好处:如果在一段代码里面用了两种 clock 的 time_point,不用担心混用在一起,编译器会报错。
有三种标准的 clock,但是只有两种需要关心,第三种可以忽略。
- 和 calender 相关的,必须使用 system_clock
- steady_clock 就像一个秒表,但是不能告诉你现在的时间
例子:
auto tp1 = steady_clock::now();
// ...
auto tp2 = steady_clock::now();
std::chrono::duration<double> diff = tp1 - tp1;
cout << diff.count() << "s\n";
Examples (49:52)
需要输出 ns 还是 s,还是 ms, 可以很简单。
using namespace std::chrono;
auto t0 = steady_clock::now();
auto t1 = steady_clock::now();
cout << nanoseconds{ t1 - t0 }.count() << "ns\n";
cout << duration<double>{ t1 - t0 }.count() << "s\n";
cout << duration_cast<milliseconds>(t1 - t0).count() << "ms\n";
上面两个是等价的。
![]()
注意:这(1970-1-1)也可能会被改变,尽管目前还是事实上的标准。