理解问题:预编译头和包含用法

5 c++ include precompiled-headers

我遇到了有关预编译标头和#include指令的用法的理解问题。所以我在这里得到了“ stdafx.h”,并在其中包含了例如vector,iostream和string。显然,关联的“ stdafx.cpp”仅包含“ stdafx.h”。

因此,如果我设计自己的头文件使用例如vector或iostream中的“代码”,则必须包含头文件,因为编译器当时不知道声明。那么,为什么这里的某些帖子(在头文件或源文件中包含stdafx.h?)说,即使该文件包含了所需的例如vector的声明,在其他头文件中包含“ stdafx.h”也是不好的吗?因此,基本上没有关系直接包含向量或预编译的头文件都一样。

我当然知道,如果关联的源文件包含所需的头文件,则不必在另一个头文件中包含头文件,因为那时声明是已知的。好吧,这仅在头文件包含在某处的情况下才有效。

所以我的问题是:我应该避免在任何源文件中包含预编译的头文件,为什么?我有点困惑,因为我在网上阅读矛盾的表达,我无论如何都不应该在头文件中包含任何内容,或者可以在头文件中包含它吗?那现在怎么了?

Who*_*aig 5

这将是一个有意图的笼统声明。Visual Studio 项目中 PCH 的典型设置遵循此一般设计,值得回顾。那是说:

  1. 设计你的头文件就好像没有 PCH 主头一样。
  2. 切勿在标头中构建包含顺序依赖项,因为您希望包含源文件会在标头之前满足这些依赖项。
  3. 尽管有 PCH 主标头(我稍后会介绍),但始终在源文件中的标准标头之前包含自定义标头。这使得您的自定义标头更有可能被正确定义,并且不依赖于包含源文件之前包含的某些标准头文件。
  4. 始终设置适当的包含防护或编译指示以避免多重包含。它们对于其正常工作至关重要。

PCH 主标头不应包含在您的头文件中。设计标头时,目的是包含标头编译所需的所有内容(并且包含所需的内容) 。如果包含源文件需要额外的包含来实现它,它可以根据需要将它们拉入标头之后。

以下是我如何设置在 .h 和 .cpp 文件中使用多个标准标头的项目的示例。

myobject.h

#ifndef MYAPP_MYOBJECT_H
#define MYAPP_MYOBJECT_H

// we're using std::map and std::string here, so..
#include <map>
#include <string>

class MyObject
{
    // some code

private:
    std::map<std::string, unsigned int> mymap;
};

#endif
Run Code Online (Sandbox Code Playgroud)

请注意,无论使用或不使用 PCH,上述标头都应在包含的任何 .cpp 中进行编译。进入源文件...

myobject.cpp

// apart from myobject.h, we also need some other standard stuff...

#include "myobject.h"
#include <iostream>
#include <fstream>
#include <algorithm>
#include <numeric>

// code, etc...
Run Code Online (Sandbox Code Playgroud)

Notemyobject.h并不期望您包含它所依赖的东西。它没有在标头中使用<iostream>or<algorithm>等​​;我们在这里使用它。

这是没有 PCH 的典型设置。现在我们添加PCH主机


添加 PCH 主标头

那么我们如何设置 PCH 主标头来加速这个东西呢?为了这个答案,我只处理引入标准头文件和第三方库头文件,这些头文件不会随着项目开发而发生变化。你不会进行编辑<map><iostream>(如果是的话,请检查一下你的头脑)。反正...

  1. 请参阅此答案,了解 PCH 通常如何在 Visual Studio 中配置。它显示了一个文件(通常stdafx.cpp)如何负责生成 PCH,其余源文件然后通过包含 来使用所述 PCH stdafx.h

  2. 决定 PCH 中的内容。作为一般规则,这就是您的 PCH 的配置方式。将非易失性内容放入其中,其余部分留给常规源包含。我们正在使用许多系统标头,这些将成为我们的 PCH 主控的选择。

  3. 确保参与 PCH Turbo 模式的每个源文件首先包含 PCH 主标头,如 (1) 中的链接答案中所述。

因此,首先是 PCH 主标头:

stdafx.h

#ifndef MYAPP_STDAFX_H
#define MYAPP_STDAFX_H

// MS has other stuff here. keep what is needed

#include <algorithm>
#include <numeric>
#include <iostream>
#include <fstream>
#include <map>
#include <string>

#endif
Run Code Online (Sandbox Code Playgroud)

最后,将源文件配置为使用此功能,然后执行此操作。所需的最小改变是:

更新:myobject.cpp

#include "stdafx.h" // <=== only addition
#include "myobject.h"
#include <iostream>
#include <fstream>
#include <algorithm>
#include <numeric>

// code, etc...
Run Code Online (Sandbox Code Playgroud)

注意我说的是最小的。实际上,这些标准标头都不再需要出现在 .cpp 中,因为 PCH 主控正在将它们拉入。换句话说,您可以这样做:

更新:myobject.cpp

#include "stdafx.h"
#include "myobject.h"

// code, etc...
Run Code Online (Sandbox Code Playgroud)

选择或不选择取决于你。我更喜欢保留它们。是的,它可以延长源文件的预处理阶段,因为它会拉入标头,进入包含防护,并丢弃所有内容,直到最终的#endif. 如果你的平台支持#pragma once(VS 也支持),那么这几乎是无操作的。

但请不要误会:这一切中最重要的部分是标头根本myobject.h没有更改,并且包括或不知道 PCH 主标头。它不应该如此,也不应该如此建造。