7

曾经在一个编程课上有人告诉我,C++ 通过让程序员在功能块中的任何位置声明其变量,实现了更好的可读性。这样,变量与处理它的代码部分组合在一起。

为什么我们不对包含做同样的事情?换句话说,为什么不鼓励将包含文件放在实际使用它的定义旁边?

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
}
4

3 回答 3

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指令,这也可能产生不良影响。

它也可能以不同的方式更容易出错。考虑两个定义了fforint和不同重载的头文件double。您可以int在文件开头添加一个(比如版本)并使用它,然后添加另一个并使用它。现在,如果您f(5.0)在包含第二个标头的行上方调用,则该int版本将被调用——此时编译器只有重载可用——这将是一个难以捕捉的错误。完全相同的代码行在文件的不同位置将具有完全不同的含义(诚然,情况已经如此,但在文件中的声明中,更容易找到哪个是被拾取的以及为什么)

通常,包含声明您将在组件中使用的元素,将它们放在顶部可以快速浏览依赖项列表。

于 2012-07-27T22:17:42.933 回答
4

想象一下以下文件:

#include <someheader>

namespace myns {
  void foo() {
  }

  void bar() {
    // call something from someheader:
    func();
  }
}

#include <someheader>靠近使用点可能很诱人。如果您改为编写以下内容,那就太好了:

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)。

于 2012-07-27T22:19:04.197 回答
0

不鼓励这样做,因为大多数程序员习惯于在文件顶部包含。我认为习惯的力量,并与 99% 的现有代码保持一致。

当我个人想查看包含哪些标题时,我只查看顶部。在某些可疑的特殊(谢天谢地)情况下,我可能会在整个文件中查找包含内容。

对于编译器来说,无论如何都没有区别。

于 2012-07-27T22:11:15.643 回答