避免在标题中包含chrono

Avoid including chrono in header

本文关键字:包含 chrono 标题      更新时间:2023-10-16

我使用std::chrono来跟踪从实例化到每次调用someMethod()所花费的时间。

最小样本代码如下所示:

#include <chrono>
class TestClass
{
public:
TestClass();
void someMethod();
private:
std::chrono::time_point<std::chrono::steady_clock> m_timeBegin;
};

TestClass::TestClass() :
m_timeBegin(std::chrono::steady_clock::now())
{
}
void TestClass::someMethod()
{
auto timeNow = std::chrono::steady_clock::now();
auto msSinceCreation = 
std::chrono::duration_cast<std::chrono::milliseconds>(timeNow - m_timeBegin);
}

我想去掉标题中的#include

动机

除了编译和链接时间,我主要关心的是封装。使用std:chrono仅与实现相关。为了使用Testclass,绝对不需要使用它,甚至不需要知道它涉及其中。

以下是一些可能的情况。如果使用TestClass的人决定使用std::chrono,他可以不添加#include。然后,如果将来TestClass更改的实现停止使用std:chrono(从而删除#include),则其他代码将毫无理由地停止使用编译

显然,那个忘了添加include的家伙做错了。但很明显,无论我们喜不喜欢,这种情况都会发生。

其他信息

由于它可能与某些解决方案相关,因此经常调用SomeMethod(),在我的场景中性能很重要。

如果time_point是一个自定义类型,问题就会得到解决,因为这样您就可以向前声明它,将成员更改为(唯一)指针,并将include移到.cpp文件中。然而,std类型的前向声明是未定义的行为,因此这是不可能的。这基本上给你留下了以下选项:

  • std::chrono::time_point<std::chrono::steady_clock>封装在自定义类中。然后,您可以安全地向前声明该类型,将成员更改为(唯一)指针,并将自定义类(包括<chrono>)的include移到.cpp文件中
  • 使用pimpl习惯用法,将类的整个实现移动到.cpp文件中

我理解你的动机。尽管如此,尽管你认为有人使用<chrono>并忘记包含它的场景并不牵强,但这是那个人的问题,而不是你的问题。因此,您应该考虑是否真的有必要引入一些复杂性,只是为了隐藏<chrono>标头。标准库包含通常不会造成伤害,尤其是因为它们不会引入重建影响。

正如其他人所指出的,为pimpl习惯用法或前向声明类型使用智能指针将引入另一个include,即<memory>。尽管这通常是一个比<chrono>更常见的标头,但您只是将一个include交换为另一个。因此,如果您真的想避免额外的include,您可能需要使用原始指针。但是,您必须处理其他问题,例如复制和移动操作。