请告诉我这两个指令有什么区别,哪个更适合在代码中使用?
文件 MyClass.h
#include <iostream>
#include <string>
#ifndef MYCLASS_H
#define MYCLASS_H
//class description
#endif
或者
#pragma once
#include <iostream>
#include <string>
//class description
请告诉我这两个指令有什么区别,哪个更适合在代码中使用?
文件 MyClass.h
#include <iostream>
#include <string>
#ifndef MYCLASS_H
#define MYCLASS_H
//class description
#endif
或者
#pragma once
#include <iostream>
#include <string>
//class description
根本区别在于它
#pragma once
适用于整个头文件。最初的想法#pragma once
是,在处理一个单独的翻译单元的过程中,编译器(预处理器)有权不去寻找也不打开包含#pragma once
. 正是在这种形式下,它曾经被提议标准化#pragma once
——作为加速编译的一种手段。include guards
#ifdef/#endif
当然有权不覆盖整个头文件,即 这对通常不适用于整个文件。这意味着,一般来说,编译器必须找到并打开头文件以包含未包含在#ifdef/#endif
.同时,很明显,编译器在第一次阅读时分析头文件的内容并识别
#ifdef/#endif
出从头到尾覆盖整个文件的显式惯用用法并不困难。在这种情况下,#pragma once
与 相比,它没有提供任何实际好处#ifdef/#endif
。正是出于这个原因,#pragma once
一次放弃了标准化——作为一种不会带来任何额外价值的特性(除了,也许,一个紧凑的符号和一个事实,正如@vp_arth 和@VladD 所指出的,没有必要发明唯一标识符)。因此,答案很明显 - 使用标准功能
#ifdef/#endif
并忘记非标准功能#pragma once
。也许在某些情况下你会注意到编译器(预处理器)不想根据分析优化处理#ifdef/#endif
并且使用#pragma once
确实加快了编译速度......然后,如果这对你很重要,它可能值得添加到你的文件#pragma once
中。另一个反对标准化的考虑
#pragma once
是,为了为其规范提供强有力的保证(即严格唯一的包含),必须能够可靠地确定给定#include
指令中指定路径的文件的身份。在许多现有文件系统中,此任务通常极难解决。所以要小心像“所有现代编译器都支持#pragma once
”这样天真的开创性陈述。在任何编译器中都没有谈到对严格规范的任何支持。而且,当然,也不存在编译器之间相同行为的任何保证。出于这个原因,如果你打算#pragma once
在你的代码中使用它,请将它与include guards 一起使用,而不是而不是他们。PS包括其他头文件通常“放在”你的
#ifdef/#endif
. 他们没有理由在外面。将它们留在外面,您可能会冒着压倒上述优化的风险。如果您已经在使用#ifdef/#endif
,那么在绝大多数情况下,它们应该从头到尾覆盖整个文件。可移植性
许多目前不支持的编译器
#pragma once
倾向于空集。现在大多是未开发或废弃的。enWiki 有一个包含源链接的表格。在此列表中,只有PGI不支持
#pragma once
.在 ruWiki 上列出
OracleSolarisStudio
在版本 12.5 中修复了此遗漏加速编译
这个加号很虚幻。您可能无法通过使用它来实现编译加速,编译器可以(肯定是 gcc)优化两者。
碰撞
主要的缺点
include guards
是你不能保证你想出了一个唯一的标识符。如果你从不打算收录外星人图书馆,你可以自己想出一个规则
include guards
,安心过日子。否则,它们会破坏名称空间存在的一切。
c++
简单MYCLASS_H
显然是不够的,因为它可能已经在另一个插件库中定义,或者如果你写一个库,在客户端代码中。您将不得不想出真正唯一的标识符,例如
__VENDOR_PACKAGE_MYCLASS
或__MYCLASS_%TIMESTAMP%
,以消除发生冲突的可能性。概括
当然,具体在项目中使用什么取决于您。但是,除了狂热的“
Отсутствует в стандарте
”,显然没有理由不使用更简洁的版本。PS: 您使用不当
include guards
- 它们必须覆盖整个文件,否则编译器将无法以任何方式优化它们,以免再次为该文件运行预处理器。该指令
#pragma once
依赖于编译器的实现,因此可能不受个别编译器的支持,将被忽略。指令
#ifndef
和#define
是标准指令,因此它们在此上下文中的使用对于所有编译器都是相同的。