C++ 将所有项目头放在一个文件headers.h中是一个好主意吗?

C++ 将所有项目头放在一个文件headers.h中是一个好主意吗?,c++,header,C++,Header,前几天我和我的导师谈过,问了他这个问题。他告诉我,我可以进行较小的项目,但我正在启动一个国际象棋程序,我想知道Stack Overflow对这个问题的看法。我应该将所有标题包含到一个文件中,还是将它们分开?一般来说,这是一个坏主意,因为在这种情况下,您可能存在无法解决的依赖项 但是,创建一个头文件通常是一个好主意,其中包含您正在使用的来自不同库的所有基本头文件或您自己的头文件(具有结构和数据类型定义)。没有万能的解决方案。以最合理的方式排列标题。90%以上的时间,这意味着每个模块只包含它需要的标

前几天我和我的导师谈过,问了他这个问题。他告诉我,我可以进行较小的项目,但我正在启动一个国际象棋程序,我想知道Stack Overflow对这个问题的看法。我应该将所有标题包含到一个文件中,还是将它们分开?

一般来说,这是一个坏主意,因为在这种情况下,您可能存在无法解决的依赖项


但是,创建一个头文件通常是一个好主意,其中包含您正在使用的来自不同库的所有基本头文件或您自己的头文件(具有结构和数据类型定义)。

没有万能的解决方案。以最合理的方式排列标题。90%以上的时间,这意味着每个模块只包含它需要的标题。然而,一些程序在模块之间几乎并没有数据结构的隔离,这可能意味着可以使用

#include "alltheheaders.h"

通常,您需要单独的标题

包含超出必要的内容会造成一些潜在的负面影响

  • 这是编译速度慢的一个最大原因。不必要地包含额外的头文件会降低编译速度,因为每个源文件都需要考虑比它需要的更多的信息。它从一个小问题开始,在你意识到它之前,数百名开发人员每个人都在浪费几十到几百个小时,因为这个问题太难解决了。即使您正在处理一些小问题,理解标题的适当分离也是很重要的——第一次很容易做到正确,但是如果忽略它,以后很难修复

  • 您失去了正确处理依赖关系的能力(取决于编译器/IDE),最终生成的信息超过了您需要生成的信息量

  • 你失去了可维护性。当你有一个大的、单一的文件时,维护软件比当你有很多小的、简洁的文件时要困难得多

  • 您使代码更难理解,因此更容易出现错误。通过将所有内容都放在一个文件中,更容易在巨大的头文件中“丢失”


  • 这种做法有时很有用:

  • 预编译的头文件,其代码实际上不会经常更改

  • 原料药


  • 对于较小的项目,您永远不会注意到差异。然而,一旦您的项目达到了相当大的规模,请坚持这句老话,“只引用直接使用它们的文件中的标题”。如果您有myclass.cpp和myclass.h,并且myclass.h不直接需要特定的头,请在cpp中引用它


    这可能需要更多的时间,但最佳实践总是值得的。

    我只想补充一点,是的,这通常是一个坏主意,但有时也会有用。但是,对于整个项目,从来没有这样做过

    例如,我最近编写了一个实用程序来在windows上执行堆栈转储。我打算包括4个常见的标题,所以我(在一个
    详细信息
    文件夹中,一个我从boost使用中偷来的约定)创建了一个
    windows.hpp
    ,其中包括这四个标题。然后,实现可以使用该头轻松地获取必要的函数


    虽然它可能不像mega-includes-480-headers头那么重要,但它是由一些常见头组成的一组,非常有用。这里的关键是,它是一个小的相关的头集合,用于代码的一部分。

    您应该将任何源(*.cpp,*.cc等)文件中包含的头数保持在编译该文件所需的最小值。包括额外的头将增加编译时间。您还应该尝试减少头中包含的数量——您可以通过向前声明类而不是包含它们的头来实现这一点

    e、 g.以下代码在标题中包含不必要的include

    Example.hh

    #include "SomeClass.hh"
    
    void SomeFunction(SomeClass const& obj);
    
    class SomeClass;
    
    void SomeFunction(SomeClass const& obj);
    
    Example.cc

    #include "Example.hh"
    
    void SomeFunction(SomeClass const& obj)
    {
       // code here
    }
    
    #include "Example.hh"
    #include "SomeClass.hh"
    
    void SomeFunction(SomeClass const& obj)
    {
       // code here
    }
    
    它可以写为将include从头文件移动到源文件

    Example.hh

    #include "SomeClass.hh"
    
    void SomeFunction(SomeClass const& obj);
    
    class SomeClass;
    
    void SomeFunction(SomeClass const& obj);
    
    Example.cc

    #include "Example.hh"
    
    void SomeFunction(SomeClass const& obj)
    {
       // code here
    }
    
    #include "Example.hh"
    #include "SomeClass.hh"
    
    void SomeFunction(SomeClass const& obj)
    {
       // code here
    }
    

    问题不同,但相关。在今天可用的硬件上,可能还有我较小的程序和模块,我已经很久没有感觉到需要预编译头了。最近我在Microsoft Visual studio 2008上使用MFC做了一个相对较小的五模块项目。MFC对象框架使编译陷入僵局,因此预编译头比不预编译头更快。尽管如此,我还是将预编译数据的读取记录为几秒钟。@mjv:我们主要产品的解决方案包含>350000 LOC。即使使用双四核机器、16 GB RAM和条带RAID磁盘,我们也很难将编译时间保持在调试构建的10分钟以下。在发布版本中,全局优化链接还需要15分钟。如果没有预编译的头文件,我想我们会在这里坐上几个小时。此外,选择性地包含头文件会增加一个自我调节的组件:当您要向文件添加新功能时,如果您正在使用的代码需要添加另一个头文件,则包括,您可以考虑它实际上是否适合于该文件,或者将更好地实现在其他地方。并且它与预编译头文件相融合,因为每当更改任何头文件时,单个头文件都会发生更改。这意味着它必须重新进行预编译(参见Reed的第1点)。我根据工作项目的经验和花在分析构建问题上的大量时间编辑了#1。我的印象是(2)实际上比(1)更浪费程序员时间。我很少坐着等待一个大型项目的完整构建。我经常坐在那里等待部分构建。当然,包括您不使用的内容会增加大量时间,但重新构建不需要的对象文件会增加增量构建时间的倍数。因此,触摸任何标题,实际上你需要一个完整的重建。另一种方法是故意将依赖项弄错,并依赖于记住真正需要重建的内容。不管怎样:啊