视频笔记:CppCon 2016: Howard Hinnant “A <chrono> Tutorial"

转载请说明出处 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();
    f();
    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)也可能会被改变,尽管目前还是事实上的标准。

 
 
 
 
 
 
 

posted on 2017-05-16 22:03  eagle-dai  阅读(302)  评论(0)    收藏  举报

导航