doc*_*doc 50 c c++ pragma include-guards
我目前正在开展一个大型项目并且维护所有这些包括警卫让我疯狂!手工编写是令人沮丧的浪费时间.虽然许多编辑可以生成包含警卫,但这并没有多大帮助:
编辑器根据文件名生成保护符号.如果在不同目录中具有相同文件名的标头,则会出现此问题.他们两个都会得到相同的包括后卫.将目录结构包含在保护符号中需要编辑器的一些奇特的方法,因为宏中的斜杠和反斜杠不是最好的.
当我必须重命名文件时,我应该重命名所有包含警戒(在ifndef中,定义和理想的endif的注释).烦人.
预处理器充斥着大量的符号,而不知道它们的含义.
然而,定义包含一次,编译器每次遇到标题包含时仍会打开标题.
包含防护不适合命名空间或模板.实际上他们正在颠覆命名空间!
你的守卫符号有可能不是唯一的.
当程序在单个目录中包含少于1000个标头时,它们可能是可接受的解决方案.但是现在呢?它很古老,与现代编码习惯无关.令我困扰的是,这个问题几乎可以通过#pragma once指令完全解决.为什么不是标准?
CB *_*ley 50
像这样的指令#pragma once以完全可移植的方式定义并不是一件容易的事情,它具有明显的明确的好处.它提出问题的一些概念在所有支持的系统上都没有很好地定义C,并且以简单的方式定义它可能没有提供超过传统包含保护的好处.
编译遇到时#pragma once,如何识别此文件以使其不再包含其内容?
显而易见的答案是文件在系统上的唯一位置.如果系统具有所有文件的唯一位置,但很多系统提供的链接(符号链接和硬链接)意味着"文件"没有唯一的位置,那么这很好.该文件是否应该重新包含,因为它是通过不同的名称找到的?可能不是.
但现在有一个问题,如何#pragma once以一种在所有平台上具有确切含义的方式定义行为- 甚至那些甚至没有目录,更不用说符号链接的方式 - 并且仍然在系统上获得理想的行为有他们吗?
您可以说文件标识由其内容决定,因此如果包含的文件包含a #pragma once且文件包含的内容完全相同,则第二个和后续的#includes将无效.
这很容易定义,并且具有良好定义的语义.它还具有良好的属性,如果项目从支持和使用文件系统链接的系统移动到不支持和使用的系统,它仍然表现相同.
在缺点方面,每次遇到包含#pragma once其内容的包含文件时,必须使用#pragma once目前已包含的文件检查每个其他文件.这意味着#include在任何情况下都会出现类似于使用警卫的性能损失,并且给编译器编写者带来了不可忽视的负担.显然,这个结果可以缓存,但传统的包含守卫也是如此.
常规包括防护程序强制程序员选择一个宏作为包含文件的唯一标识符,但至少行为定义明确且易于实现.
鉴于潜在的陷阱和成本,以及传统包括警卫确实有效的事实,标准委员会认为不需要标准化也就不足为奇了#pragma once.
Mic*_*urr 19
包含警卫肯定是一个烦恼,C应该最初设计为默认情况下将包含一次标题 - 需要一些特殊选项来多次包含标题.
然而,它不是,你大部分时间都不得不使用包含警卫.也就是说,#pragma once它得到了广泛支持,因此您可以放心使用它.
就个人而言,我通过向包含守卫添加GUID来解决您的第一个问题(类似地命名为包含文件).这很丑陋,而且大多数人都讨厌它(所以我经常被迫不在工作中使用它),但是你的经验表明这个想法有一些价值 - 即使它很丑陋(但是整个包括后卫的东西是什么样的黑客 - 为什么不全力以赴?):
#ifndef C_ASSERT_H_3803b949_b422_4377_8713_ce606f29d546
#define C_ASSERT_H_3803b949_b422_4377_8713_ce606f29d546
// blah blah blah...
#endif
Run Code Online (Sandbox Code Playgroud)
我听说编译器实际上没有重新打开包含警卫的头文件(他们已经学会识别成语).我不确定这是真的(或者它的真实程度); 我从未测量过它.我也不担心,但我的项目不是很大,这是一个问题.
我的GUID hack几乎解决了第1项,第5项和第6项.我只使用第2,3和4项.实际上,对于第2项,当您重命名文件时,您可以在不重命名包含保护宏的情况下生存,因为GUID将确保它仍然是独特的.实际上,没有理由将文件名完全包含在GUID中.但我认为 - 传统,我想.
jmu*_*llo 14
名称空间和模板不应跨越标题.亲爱的,不要告诉我你这样做:
template <typename foo>
class bar {
#include "bar_impl.h"
};
Run Code Online (Sandbox Code Playgroud)你已经说过了.
正如已经指出的那样,C++标准应该考虑到不同的开发平台,其中一些可能有限制使得#pragma一旦支持无法实现.
另一方面,由于之前类似的原因,没有添加对线程的支持,但是较新的C++标准包括线程.在后一种情况下,我们可以针对一个非常有限的平台进行交叉编译,但是开发是在一个成熟的平台上完成的.由于GCC支持这种扩展,我认为,你的问题的真正答案是没有兴趣的人将此功能推入C++标准.
从实际的角度来看,包括守卫在内,比#pragma once指令不合规更让我们的团队陷入困境.例如,如果文件重复并且稍后包含两个副本,则包含保护中的GUID不起作用.只使用#pragma一旦我们得到重复的定义错误并且可以花时间统一源代码.但是在包含保护的情况下,问题可能需要运行时测试来捕获,例如,如果副本在函数参数的默认参数上不同,则会发生这种情况.
我避免使用包含警卫.如果我必须在没有#pragma支持的情况下将代码移植到编译器,我将编写一个脚本,它将向所有头文件添加包含防护.
| 归档时间: |
|
| 查看次数: |
7900 次 |
| 最近记录: |