是Visual Studio上必需的“冗余#include后卫”?

问题描述:

我用下面的代码,以确保包括文件不加载超过一次。是Visual Studio上必需的“冗余#include后卫”?

#ifndef _STRING_ 
#include <string> 
#endif 

// use std::string here 
std::string str; 
... 

这个技巧在“API Design for C++”一书中说明。

现在我的共同工作告诉我,在Visual Studio中这不是必需的,因为如果字符串的实现头文件包含#pragma once,则不需要包含保护来提高编译速度。

这是正确的吗?从原书

报价:

7.2.3 Redundant #include Guards 
Another way to reduce the overhead of parsing too many include files is to add redundant preprocessor 
guards at the point of inclusion. For example, if you have an include file, bigfile.h, that looks 
like this 
#ifndef BIGFILE_H 
#define BIGFILE_H 
// lots and lots of code 
#endif 
then you might include this file from another header by doing the following: 
#ifndef BIGFILE_H 
#include "bigfile.h" 
#endif 
This saves the cost of pointlessly opening and parsing the entire include file if you’ve already 
included it. 
+0

http://compgroups.net/comp.lang.c++.moderated/sutters-guidelines-and-redundant-incl/18725 – q0987 2013-02-27 18:59:57

+0

http://books.google.com/books?id=mmjVIC6WolgC&pg=PT18&lpg=PT18&dq = Always + write + internal +%23include + guards + Never + write + external +%23include + guards&source = bl&ots = ccUmMSdLTa&sig = RSuH_-06Em9V02D94PTQULL_m3U&hl = en&sa = X&ei = 01cuUau1OYTy2QWnzoGgCQ& ved = 0CGgQ6AEwCA – q0987 2013-02-27 19:02:38

+0

'#pragma once'的使用会引发相同的优化由所有主要编译器。我建议使用它。许多编译器(至少gcc和vs)都使用标准的内部包含守卫来实现相同的优化。我希望那是你正在阅读的一本旧书。多年来,冗余外部警卫对主要编译器的用户没有任何好处。 – John 2017-08-07 19:32:35

#pragma once是一个包括后卫的一个更好的形式。如果您使用它,则不需要基于#define的包含警卫。

在一般情况下,这是一种更好的方法,因为它可以防止名称冲突,从能够打破一个包括后卫。

话虽这么说,在包括后卫应该在头文件,而不是包裹包括。包装应该是完全不必要的(并且可能会混淆其他人)。


编辑:

我认为我们是在谈论两个不同的东西。我的问题是当我们使用预先存在的头文件时,是否应该使用包含guard的#pragma once或#ifndef xxx

在这种情况下,如果标题有适当的警卫,则没有理由避免包含它。这只会增加混乱和复杂性。

+0

我不推荐使用'#pragma once',它会导致不可移植的代码... – 2013-02-27 18:22:12

+0

@ g-makulik您使用哪些编译器不支持它?它几乎支持所有主流的现代C++编译器。 – 2013-02-27 18:25:21

+0

我正在使用嵌入式的东西。 – 2013-02-27 18:33:00

您不需要需要这样做,因为任何由有经验的开发人员编写的头文件都会有自己的保护。你可以假设标准库头由主管工程师写的,如果你发现自己使用的是第三方头不包括警卫......嗯,第三方现在高度怀疑......

至于写你自己的头,你可以使用标准:

#ifndef MY_HEADER_H 
#define MY_HEADER_H 

// ...code 

#endif 

或者只是使用:

#pragma once 

请注意,这不是标准C或C++,它是一个编译器扩展。它不适用于那里的每个编译器,但使用它是您的决定,并取决于您的预期用途。

+0

我认为我们正在谈论两件不同的事情。我的问题是,当我们使用一个已经存在的头文件时,是否应该使用include guard,该头文件有#pragma once或#ifndef xxx – q0987 2013-02-27 18:17:37

+0

@ q0987:我们不是在谈论不同的事情。你所显示的代码是*不是*你如何使用include guard并且完全没有必要。你需要明白,如果一个头文件包含一个包含守卫(他们都会这样做),它可以不包含两次。这就是为什么你的方法是错误的。你的书完全错了。要么你误解了它,要么这本书不好。 – 2013-02-27 18:18:12

+0

检查我更新的OP。 – q0987 2013-02-27 18:21:12

这并不包括如何使用警卫。你不会把你的#include包装在一名包括后卫中。头文件应该将自己的内容封装在一个包含守护程序中。每当你写的可能会被包含在其他文件中,你应该做的:

#ifndef _SOME_GUARD_ 
#define _SOME_GUARD_ 

// Content here 

#endif 

与Visual Studio的实现C++库中,可能具有#pragma oncestring头或检查#ifndef _STRING_来完成。

+0

而且,当然,您不会给像'_SOME_GUARD'这样的包含保护名称,因为以下划线开头的名称后跟一个大写字母以及包含两个连续下划线的名称将保留给实施。 – 2013-02-27 19:56:45

一般术语“包括后卫”意味着这个#ifdef#define#endif序列被置于围绕一个特定的头文件里面的内容此文件。

一些C++编译器提供了#pragma once语句,以保证外部具有相同的行为。但为了便携式C/C++代码,我不鼓励使用它。

UPDATE(根据OP的编辑)
另外把#ifdef#endif各地在另一个文件中#include声明可能会阻止预处理器从打开包含文件本身(从而减少编译时间和内存使用情况略)。我期望#pragma once会自动做到这一点,但不能肯定(这可能是特定于实现)。

+1

这正是我觉得本书作者试图传达的东西! – q0987 2013-02-27 18:47:47

+2

@ q0987但是,这种行为可能特定于编译器实现。我希望一个很好实现的预处理器以某种方式缓存已打开和解析的包含文件,从而使这个技巧无关紧要。 – 2013-02-27 18:54:53

冗余包括守卫,顾名思义,“冗余”。它们不会影响通过编译创建的二进制文件。但是,他们确实有一个好处。冗余包括守卫可以减少编译时间。

谁在乎编译时间?我在意。我只是一个开发人员,是数百名开发人员的项目,拥有数千个源文件中的数百万行源代码。完成重建项目需要45分钟。从版本控制拉的增量版本需要20多分钟。由于我的工作取决于这个大项目,所以在等待这个长时间的构建时,我无法进行任何测试。如果这个建造时间缩短到5分钟以内,我们公司将受益匪浅。假设构建时间节省20分钟。 1年* 100位开发人员*每天1次建造,* 1/3小时/建造* 250天/年* 50美元/小时=每年节省416,667美元。有人应该关心这一点。

对于Ed S,我一直使用冗余包括守卫10年。偶尔你会发现有人使用这种技术,但最害羞的是因为它可能会制造丑陋的代码。 “#pragma曾经”肯定看起来更清洁。百分比方面,很少有开发者通过继续他们的教育和技术不断尝试提高他们的才能。多余的#include警卫技术有点模糊,只有当有人不愿意对大型项目进行分析时才会意识到它的好处。你知道有多少开发者会采用先进技术来购买C++书籍?

回到最初关于Redundant的问题在Visual Studio中包含guard和#pragma一次......根据Wiki #pragma once,支持“#pragma once”的编译器可能更有效率,因为它们可以分析#include警卫文件名和路径,以防止加载已加载的文件。有三个编译器被称为具有这种优化。 Visual Studio中显然没有这个列表。所以,我们仍然想知道在Visual Studio中是否应该使用多余的#include警卫或者#pragma一次。

对于中小型项目,#pragma一次肯定方便。对于编译时间成为开发过程中因素的大型项目,多余的#include警卫让开发人员更好地控制编译过程。管理或架构大型项目的任何人都应该在他们的库中有Large Scale C++ Design - 它会讨论并建议多余的#include警卫。

可能比冗余更大的好处包括守卫是智能使用#includes。随着C++模板和STL变得越来越流行,方法实现正在从.cpp文件迁移到.h文件。 .cpp实现可能具有的任何头文件依赖关系现在都必须迁移到.h文件。这增加了编译时间。我经常看到开发人员将大量不必要的#include堆栈到它们的头文件中,这样他们就不必费心识别它们实际需要的头文件。这也增加了编译时间。