我正在读一本关于Applied C++的书.
包含防护将阻止在编译源文件期间多次包含头文件.您的符号名称应该是唯一的,我们建议您根据文件名选择名称.例如,我们的文件cache.h包含这个包含保护.
#ifndef _cache_h_
#define _cache_h_
...
#endif // _cache_h_
Run Code Online (Sandbox Code Playgroud)
Lakos描述了使用冗余包含警卫来加速编译.见[Lakos96].对于大型项目,打开每个文件需要花费时间,但却发现已经定义了包含保护符号(即,文件已经包含在内).编译时间的影响可能是戏剧性的,当只使用标准的包含防护时,Lakos显示编译时间可能增加20倍.
[Lakos96]:LargeScale C++软件设计.
我没有Lakos96参考书来引用概念,所以在这里寻求帮助.
我对上述文字的疑问是
作者的意思是"对于大型项目,打开每个文件需要花费时间,但却发现已经定义了包含保护符号"?
作者的意思是"当标准包括使用警卫时"?
谢谢你的时间和帮助.
来自C++编码标准(Sutter,Alexandrescu)
许多现代C++编译器自动识别标题保护(参见条款24),甚至不打开两次相同的标题.有些还提供预编译头文件,这有助于确保不经常解析经常使用的,很少更改的头文件
所以,我会认为这些建议已经过时(除非你还在使用一些非常过时的编译器).
至于你的问题:
什么是冗余编译保护?
一个天真的编译器会在每次包含文件时重新加载该文件.为避免这种情况,请在include:header.h周围放置RedundantIncludeGuards
#ifndef HEADER_H_
#define HEADER_H_
// declarations
#endif
Run Code Online (Sandbox Code Playgroud)
foo.c的
#ifndef HEADER_H_
#include "header.h"
#endif
Run Code Online (Sandbox Code Playgroud)
在这里阅读更多.您的参考声称,通过这样做,您在编译期间的速度可能比foo.c仅执行时快20%
#include "header.h"
Run Code Online (Sandbox Code Playgroud)
我不知道Lakos96说的是什么,但无论如何我都要猜测......
标准包括警卫就像:
#ifndef FOO_H_INCLUDED
#define FOO_H_INCLUDED
....
#endif
Run Code Online (Sandbox Code Playgroud)
包含文件时,冗余包含Guard正在使用宏:
#ifndef FOO_H_INCLUDED
#include "foo.h"
#endif
Run Code Online (Sandbox Code Playgroud)
这样第二次foo.h包含文件时,编译器甚至不会在磁盘中搜索它.因此加速:想象一个大型项目,一个单独的编译单元可能包含foo.h100次,但只有第一个将被解析.其他99次将被预编译器搜索,打开,标记化,丢弃并关闭.
但请注意,那是在1996年.今天,GCC,给出一个众所周知的例子,具有特定的优化,识别包含保护模式,并使冗余包括保护,嗯......,冗余.
拉科斯的书很旧.这可能是真的一次,但你应该在你的机器上计时.许多人现在不同意他,例如 http://www.allankelly.net/static/writing/overload/IncludeFiles/AnExchangeWithHerbSutter.pdf 或http://c2.com/cgi/wiki?RedundantIncludeGuards 或http:// gamearchitect.净/文章/ ExperimentsWithIncludes.html
Herb Sutter,C++大师和ISO C++标准委员会的现任主席,反对外部包括警卫:
"顺便说一下,我强烈不同意拉科斯的外部包括两名警卫:
大多数编译器都没有任何好处.我承认我还没有做过测量,因为Lakos似乎已经做过了,但据我所知,今天的编译器已经有了智能,以避免重建开销的构建时间 - 即使MSVC做了这个优化(尽管它需要你说"#pragma once"),它在很多方面都是最弱的编译器.
外部包括防护违反封装,因为它们需要许多/所有呼叫者知道标头的内部 - 特别是用作防护的特殊#define名称.它们也很脆弱 - 如果你的名字错了怎么办?如果名字改变怎么办?"