改进基于<chrono>

Improving a timer class based on <chrono>

本文关键字:chrono gt lt      更新时间:2023-10-16

我有以下Timer类来简化获取自epoch以来经过的时间:

#include <chrono>
class Timer {
public:
void start(void);
template <typename duration_type>
const duration_type time_elapsed(void);
private:
std::chrono::high_resolution_clock::time_point epoch;
};
void Timer::start(void) {
epoch = std::chrono::high_resolution_clock::now();
}
template <typename duration_type>
const duration_type Timer::time_elapsed(void) {
return std::chrono::duration_cast<duration_type>(std::chrono::high_resolution_clock::now() - epoch);
}
int main(void) {
Timer timer;
timer.start();
// pointless loop to cause a delay
for (int x = 1; x < 1000000; ++x) {
x * x * x;
}
std::chrono::nanoseconds elapsed = timer.time_elapsed<std::chrono::nanoseconds>();
std::cout << elapsed.count() << std::endl;
return 0;
}

我有一种感觉,我把Timer::time_elaped()作为一个模板函数,这使我的类过于复杂了,理想情况下,我想把它的用法简化为:

std::chrono::nanoseconds elapsed = timer.time_elapsed();
std::cout << elapsed.count() << std::endl;

我修复了代码中的一些内容,并添加了std::chrono的正确用法。更改列表包括:

  1. 我从函数调用中删除了所有(void)参数,因为它不是C++方式:-)
  2. 我还从main()中删除了C++中不需要的return 0;,因为编译器会为您放置它
  3. 我键入了一个时钟,因为现在在当前的实现中可能很难找到一个高质量的时钟。请在此处查看我的答案。基本上,现在您可能想要使用自定义时钟,并且由于typedef,重构在未来可能会更容易
  4. 我把你的等待循环改成了C++11睡眠接口(如果你愿意,你可以在那里随机分配一些持续时间——也可以用C++11:-)。在这种情况下不需要这种更改,但它很好地展示了std::chrono在线程库中的使用
  5. 我把你的方法实现放在一个类中,让编译器有机会内联它们。或者,您可以在类之外的实现中使用inline关键字explicity
  6. 我做了你的time_elapsed()方法const
  7. 我从time_elapsed()方法的返回值中删除了不必要的const,另一方面在使用该方法时添加了它,因为在那个确切的地方const就足够了
  8. 最后但同样重要的是,我修改了您的time_elapsed()方法,以在return中返回时钟的本机分辨率。这是一个更好的解决方案,因为您永远不会在这里丢失数据。当向特定单元(即我们)中的用户提供数据时,您可能想要放松它。你必须在那里使用duration_cast来告诉编译器你同意丢失一些数据,我们的分辨率对你来说已经足够了

我希望下面的代码和上面的更改会让你感兴趣。

#include <chrono>
#include <thread>
#include <iostream>
using namespace std::chrono;
class Timer {
public:
typedef high_resolution_clock Clock;
void start()
{ epoch = Clock::now(); }
Clock::duration time_elapsed() const
{ return Clock::now() - epoch; }
private:
Clock::time_point epoch;
};
int main() {
Timer timer;
timer.start();
// sleep some time
std::this_thread::sleep_for(microseconds(40));
const auto elapsed = timer.time_elapsed();
std::cout << duration_cast<microseconds>(elapsed).count() << "us" << std::endl;
}

顺便说一句,我不想玩类接口(我已经做了太多的更改)。如果你还没有绑定到那个接口,我建议你使用@sehe建议的接口。但不要将该double用作返回值;-)

返回一个助手类,该类存储now-egic(),并根据经过的时间对运算符T执行高精度强制转换。或者,有一个time_elapsed_in_units<T>方法,看起来像你的时间流逝,然后让时间流逝返回一个结构,该结构以单位调用运算符T.

通过重载helper类的运算符T,可以隐式地检测被调用方想要的类型。