C++11标准时间库:chrono常用类的理解与使用(一)—— duration
定义
template<
class Rep,
class Period = std::ratio<1>
> class duration;
说明:
此类模板由类型为Rep的tick计数和一个tick周期组成,其中tick周期是从一个tick到下一个tick所表示的秒数的编译时有理分数。duration中仅存储了类型为Rep的tick计数。如果Rep是浮点数,则duration可以表示tick的分数部分。Period作为duration类型的一部分包含在内,在不同duration之间进行转换时才会使用。
老黑的大白话解释:
duration字面意思是“持续时间”,该模板有两个成员类型:
- Rep:表示tick(嘀嗒)的数量
- Period:表示tick的周期。
其中,Period的默认单位是1秒,也就是std::ratio<1>;
换句话说,如果我们想要一段表示10秒的duration,可以将Rep指定为10,ratio指定为1。比如我们希望让线程sleep 10秒:
std::chrono::duration<int64_t, std::ratio<1>> d(10);
std::this_thread::sleep_for(d);
当然,我们一般不需要自己指定Period参数,标准库已经定义好了一些类型:
/// nanoseconds
typedef duration<int64_t, nano> nanoseconds;
/// microseconds
typedef duration<int64_t, micro> microseconds;
/// milliseconds
typedef duration<int64_t, milli> milliseconds;
/// seconds
typedef duration<int64_t> seconds;
/// minutes
typedef duration<int64_t, ratio< 60>> minutes;
这里的nano、micro、milli即std::nano,std::micro,std::milli类型。
类型的声明如下:
typedef ratio<1, 1000000000> nano;
typedef ratio<1, 1000000> micro;
typedef ratio<1, 1000> milli;
ratio第一个模板参数num(分子),第二个参数den(分母),我们之前提到,duration默认单位是1秒。因此,Period指定为ratio<1, 1000>,则Period是1/1000秒,即1 毫秒(millisecond)。
需要线程sleep 10秒,我们也可以使用以下可读性更好的写法(直接创建一个匿名对象即可):
std::this_thread::sleep_for(std::chrono::seconds(10));
std::this_thread::sleep_for(std::chrono::milliseconds (10 * 1000));
std::this_thread::sleep_for(std::chrono::microseconds (10 * 1000 * 1000));
常用成员函数或非成员函数
- count
constexpr rep count() const
返回Rep的值,即tick的计数。
例子:
duration<int>(100).count(); /** 此例返回100 */
- duration_cast
template <class ToDuration, class Rep, class Period>
constexpr ToDuration duration_cast(const std::chrono::duration<Rep,Period>& d);
将std::chrono::duration转换为与duration类型不同的ToDuration。
注意:
对于整数duration来说,如果源Period可以被目的Period整除(例如小时到分钟)或浮点数duration之间的强制类型转换可以通过普通的类型转换或隐式地通过std::chrono::duration构造函数来执行,不需要使用duration_cast。
当浮点值为NaN、无穷大或太大无法由目标整数类型表示时,将浮点时间段转换为整数时间段会出现未定义的行为。否则,将其转换为整数时间段可能会受到截断的影响,就像对于任何静态类型转换为整数类型一样。
参考cppreference中的例子进行解释
#include <iostream>
#include <chrono>
#include <ratio>
#include <thread>
void f()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
}
int main()
{
auto t1 = std::chrono::high_resolution_clock::now();
f();
auto t2 = std::chrono::high_resolution_clock::now();
// 浮点 duration:不需要使用duration_cast
std::chrono::duration<double, std::milli> fp_ms = t2 - t1;
// 整数 duration: 需要使用duration_cast
auto int_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);
// 将整数 duration 转换为更小的可整除的时间单位:(如毫秒到微秒)
// 不需要使用duration_cast
std::chrono::duration<long, std::micro> int_usec = int_ms;
std::cout << "f() took " << fp_ms.count() << " ms, "
<< "or " << int_ms.count() << " whole milliseconds "
<< "(which is " << int_usec.count() << " whole microseconds)" << std::endl;
}
为了更好的理解这个注意事项,我们看一下这个例子中定义的“-”运算符的形式:
template<typename _Clock, typename _Dur1, typename _Dur2>
constexpr typename common_type<_Dur1, _Dur2>::type
operator-(const time_point<_Clock, _Dur1>& __lhs,
const time_point<_Clock, _Dur2>& __rhs)
{ return __lhs.time_since_epoch() - __rhs.time_since_epoch(); }
这个运算符的返回值是一个左侧time_point对象的time_since_epoch()减去右侧time_point对象的time_since_epoch()(说明:std::chrono中的clock's epoch是指时钟开始测量时间的时间点)。
我们并不会在这篇博客中讲解什么是time_point类(这是下一篇博客的内容:),因此只需要暂时感性认识为,两个时间点的差值就是一段duration。如果需要把这种差值转换为指定形式的整数形duration,则需要使用duration_cast。