我曾经在编程类中告诉过,C ++通过让程序员在函数块中的任何地方声明其变量来实现更好的可读性。这样,变量就与处理它的代码部分组合在一起。
为什么我们不对包含做同样的事情? 换句话说,为什么不鼓励将include文件放在实际使用它的定义旁边?
parser::parser()
{
// some initialization goes there which does not make use of regex
}
#include <boost/regex.hpp>
parser::start()
{
// here we need to use boost regex to parse the document
}
答案 0 :(得分:8)
其中一个原因是#include
是无上下文的,它们只是纯文本包含,并且在代码中间使用它可能会产生一些不必要的影响。例如,考虑您有一个命名空间,并且此文件中的所有代码都属于命名空间:
// Include on demand:
namespace ns {
void f() {} // does not need anything
//... lots of other lines of code
#include <vector>
void g() { std::vector<int> v; }
}
现在甚至可以编译好......而且错误。因为包含在命名空间内,所以文件的内容被转储到ns
内,并且包含的文件声明/定义::ns::std::vector
。因为它只是标题,它甚至可以编译正常,只有当你尝试在具有不同子系统的接口中使用它时(在不同的命名空间中)才会失败 - 这可以修复,你只需关闭所有上下文,添加包含并重新打开相同的上下文...
在其他情况下,翻译单元中的代码可能会实际影响包含。例如,考虑您在翻译单元中添加了using namespace
指令。之后包含的任何标头都将具有using namespace
指令,这也可能产生不需要的效果。
它也可能以不同的方式更容易出错。考虑两个标头,为f
和int
定义double
的不同重载。您可以在文件的开头添加一个(比如int
版本)并使用它,然后添加另一个并使用它。现在,如果您在包含第二个标题的行上方调用f(5.0)
,则会调用int
版本 - 此时编译器只能使用过载 - 这将很难捕获错误。完全相同的代码行在文件的不同位置具有完全不同的含义(诚然已经是这种情况,但在文件中的声明中,查找更容易被选中起来,为什么)
通常,include声明将在组件中使用的元素,并将它们放在顶部,快速浏览一下依赖项列表。
答案 1 :(得分:3)
想象一下以下文件:
#include <someheader>
namespace myns {
void foo() {
}
void bar() {
// call something from someheader:
func();
}
}
将#include <someheader>
放在使用点附近可能很诱人。那将是很好的 iff 你改为编写以下内容:
namespace myns {
void foo() {
}
}
#include <someheader>
namespace myns {
void bar() {
// call something from someheader:
func();
}
}
问题出在中型/大型文件中,根据您的缩进样式,很容易忽略您在命名空间(以及其他#ifdef
s)中嵌套的程度。您可能稍后再回来并决定移动它,或者添加另一个嵌套的命名空间。
所以,如果你把#include
写在最顶层总是你不会因为不小心写下这样的东西而被咬伤:
namespace myns {
void foo() {
}
// Whoops, this shouldn't be inside myns at all!
#include <someheader>
void bar() {
// call something from someheader:
func();
}
}
这将介于错误和非常错误之间,具体取决于<someheader>
中的确切内容。 (例如,您可以通过违反具有多个定义的ODR来结束UB,尽管其他合法且相同的令牌序列匹配不同的功能,因此违反了§3.2.5)。
答案 2 :(得分:0)
这是不鼓励的,因为大多数程序员习惯于包含在文件的顶部。我认为习惯的力量,以及99%现有代码的一致性。
当我个人想看看包含哪些标题时,我只看顶部。在特殊(并且非常罕见)的情况下,有些东西是可疑的,我可能会在整个文件中寻找包含。
无论如何,对编译器没有任何区别。