我使用了一些非常大规模的系统,从未见过所需的订单,但最近遇到了。STL 或 STD 库甚至 Boost 是否存在某些包含必须以特定顺序出现的情况?
13 回答
STL 或 STD 库甚至 Boost 是否存在某些包含必须以特定顺序出现的情况?
对于标准,答案是肯定的,不。我想Boost也是如此,尽管我没有查过。
来自 C 标准:
标准标题可以以任何顺序包含;每个都可以在给定的范围内多次包含,与仅包含一次没有任何不同,除了包含的效果
<assert.h>
取决于NDEBUG
(见 7.2)的定义。
C++ 标准有类似的措辞。
我的偏好是标题应该包含它们自己的依赖项,但我曾与认为这是“浪费”的人合作过。在我看来,不让标头包含它们的依赖项是一个毫无价值的早期优化。
这听起来绝对是一个糟糕的设计。如果以某种方式需要特定顺序,则库应提供一个标头,其中包含按正确顺序的其他标头。
至于 boost 和 STL,我很确定我还没有遇到过这种情况。
需要以特定顺序指定包含几乎总是表明存在设计问题。减少无意中执行此操作的可能性的一种方法是练习将类的头文件作为第一个#include 包含在实现文件中。
// A.cpp
#include "A.h"
#include "boost/shared_ptr.hpp"
#include <vector>
class A {
// ...
};
这样,例如,如果 Ah 使用没有正确 #include 的向量,A.cpp 将无法编译。
我不记得我在哪里捡到的;它可能来自 Lakos 的“Large Scale C++ Design”(一本真正可以使用更新的好书)。
STL 或 STD 库甚至 Boost 是否存在某些包含必须以特定顺序出现的情况?
我从来没有遇到过这种情况,如果是这样,那么必须尽快通知作者。哦,是的,这是一个非常糟糕的设计。
那是“坏事”。已经提到了更好的方法;但我会详细说明。
//a.h #ifndef _A_H_ #define _A_H_ //... code ... #endif // ----------------- //b.h #ifndef _B_H_ #define _B_H_ #include a.h //... code ... #endif // ----------------- //main.cpp Try 1 #include "b.h" //<- okay! b includes a, then does b // ----------------- //main.cpp Try 2 #include "a.h" //<- includes a #include "b.h" //<- okay! b includes a, but skips redefining it, then does b // ----------------- //main.cpp Try 3 #include "b.h" //<- b includes a, then does b #include "a.h" //<- okay! a skips redefining itself! // ----------------- //main.cpp Try 4 #include "a.h" //<- fail! b is not included anywhere =(
将项目级兼容性头文件(比如 compat.h)作为任何 .c/.cpp 源文件的第一个头文件是一种常见的技术,它定义了一堆必需的宏,如 __STDC_LIMIT_MACROS、__REENTRANT 和其他项目范围的宏来影响标准标题的后续行为。
很久以前,我第一次看到这种用法是由一位称职的程序员用于内部库的。后来我看到“git”(臭名昭著的 dvcs)项目也使用了这种技术。
如果标题中包含的函数和/或类(例如,Ah)依赖于另一个标题(例如,Bh)中定义的函数和/或类,我更愿意将后者包含在第一个中,而不是强制第一个的用户一个以特定顺序包含两者。
是的:
// A.h
#pragma once
// or the #ifndef trick
#include "B.h"
// A.cpp
#include "A.h"
不:
// A.h
#pragma once
// or the #ifndef trick
//#include "B.h"
// A.cpp
#include "B.h"
#include "A.h"
我喜欢按字母顺序包含标题 - 可以轻松查看我已经完成的工作。
如果一个库因为顺序错误而无法工作,那么它就坏了,应该被修复以便与顺序无关。
对我来说,这是一个糟糕的设计,如果我没记错的话,不幸的是,它恰好在带有 socket/socket2 的 win32 API 中。结果是包含顺序中的错误将触发一组错误,这些错误恰好来自无处,并且在依赖项更改定义但代码仍然编译的情况下可能难以调试。
在任何其他情况下,您仍然会遇到麻烦。如果您不包含标头 xh 因为 yh 已经包含它,那么您的代码依赖于 yh 对 xh 的依赖 如果稍后 yh 被重构并且不再需要 yh,则删除包含将破坏您的代码库。这是耦合的标志(即使不是在类级别):代码库的一部分中的更改需要传播并扩展到代码的其他部分。
这可能表明您正在使用 MFC,这反过来又可能表明设计不佳(开玩笑……或者是吗?)
(至少,我上次看MFC的时候,对你包含的地方真的很挑剔<windows.h>
)
据我所知不是。这是非常糟糕的做法。不过,我最近在我的代码中遇到了一个 Windows 标头和一些奇怪的界面。
您应该使用包含警卫和前向声明,这样您就不应该对包含标题的顺序有太大问题。
有时仍然需要首先或最后包含标题,不知道为什么。
(例如:在源 SDK 中)
是的,要求 C++ 中包含的特定顺序是不良库/头文件设计的标志。
尽管前向声明可能需要包含多个文件才能完全使用一个类。请参见下面的示例:
//啊
class B; // forward declaration
class A
{
void doStuff(const B& b);
};
// main.cpp
#include <A.h>
#include <B.h>
int main()
{
A a;
B b;
a.doStuff(b);
}