为什么C++标准库已经预先包含在任何C++源代码中?

650*_*502 33 c++

在C++中,标准库包含在std命名空间中,程序员不应该在该命名空间内定义任何内容.当然,标准包含文件不会在标准库中相互依赖名称(因此包含标准头文件从来都不是问题).

那么为什么不是默认包含整个标准库而不是强迫程序员#include <vector>每次都编写?这也可以加快编译速度,因为编译器可以从所有标准头文件的预构建符号表开始.

预先包含所有内容也可以解决一些可移植性问题:例如,当你包含<map>它时,定义了什么符号被带入std命名空间,但是不保证其他标准符号没有被加载到它中,例如,你可能最终(理论上)与std::vector也变得可用.

有时会发生程序员忘记包含标准头文件但程序仍会编译,因为包含了特定实现的依赖性.将程序移动到另一个环境(或只是同一编译器的另一个版本)时,相同的源代码可能会停止编译.

从技术角度来看,我可以对编译器进行映像,只需预加载(带mmap)标准库的最佳完美哈希符号表.这应该比加载和执行甚至单个标准包含文件的C++解析更快,并且应该能够更快地查找std::名称.该数据也是只读的(因此可能允许更紧凑的表示并且还可以在编译器的多个实例之间共享).

然而,这些应该是我从未实现过的.

我看到的唯一缺点是我们的C++程序员会丢失编译咖啡休息和Stack Overflow访问:-)

编辑

为了澄清我看到的主要优点,对于今天的程序员来说,尽管C++标准库是一个单一的命名空间,但需要知道哪个子部分(包含文件)包含哪个函数/类.如果他们犯了错误并且忘记了包含文件,那么代码可能会编译或者根据实现(因此导致非可移植程序)编译或不编译.

Ser*_*sta 18

简短的回答是因为它不是应该使用C++语言的方式

这有很好的理由:

  • 命名空间污染 - 即使这可以减轻,因为std命名空间应该是自相关的,程序员不会被迫使用using namespace std;.但是包括整个图书馆using namespace std;肯定会导致一团糟......
  • 强制程序员声明他想要使用的模块,以避免无意中调用错误的标准函数,因为标准库现在很大并且并非所有程序员都知道所有模块
  • 历史:C++仍然有很强的继承自C,其中名称空间不存在,标准库应该用作任何其他库.

从你的意义上讲,Windows API就是一个例子,你只有一个大的include(windows.h)可以加载许多其他较小的包含文件.实际上,预编译头文件允许足够快

因此,恕我直言,一种源自C++的新语言可以决定自动声明整个标准库.一个新的主要版本也可以做到这一点,但它可能会使用using namespace指令集中破解代码,并使用与某些标准模块相同的名称进行自定义实现.

但是我所知道的所有常用语言(C#,Python,Java,Ruby)都要求程序员声明他想要使用的标准库的各个部分,所以我认为系统地提供标准库的每一部分仍然更加尴尬对程序员来说真的很有用,至少在有人发现如何声明不应该加载的部分之前 - 这就是为什么我谈到C++的新衍生物

  • 如果你有任何名称与标准库的任何标题冲突,那么`using namespace std`永远不能保证工作(原因是例如`<map>`**可以**合法地接受`std :: vector `).实际上`使用命名空间std`本身就是一个错误的错误(除了玩具示例)并且基本上违背了命名空间的目的. (8认同)

Dar*_*nas 9

大多数C++标准库都是基于模板的,这意味着它们生成的代码最终将取决于您如何使用它们.换句话说,在实例化模板之前,很少可以编译std::vector<MyType> m_collection;.

此外,C++可能是编译速度最慢的语言,当你#include的头文件也包含其他头文件时,编译器必须做很多解析工作.

  • 事实上C++是一个可怕的野兽解析是一个有利于预解析整个标准库的论据,而不是反对它. (7认同)

Ded*_*tor 6

嗯,首先,C++试图坚持"你只为你使用的东西买单".
标准库有时不是您使用的部分,甚至是您可能使用的部分.
此外,如果有理由,您可以替换它:请参阅libstdc++libc++.
这意味着毫无疑问地将它包括在内并不是一个明智的想法.

无论如何,委员会正在慢慢地创建一个模块系统(它需要很多时间,希望它适用于C++ 1z:C++模块 - 为什么它们会从C++ 0x中删除?它们会在以后再回来吗? ?),当这样做时,包含更多标准库而不是严格需要的更多缺点应该消失,并且各个模块应该更干净地排除它们不需要包含的符号.
此外,由于这些模块是预先解析的,因此它们应该提供您想要的编译速度提升.


Ste*_*sop 5

您提供的方案有两个优点:

  • 编译时性能.但是标准中没有任何内容阻止实现通过非常轻微的修改来执行您建议的[*]:预编译表仅在转换单元包括至少一个标准头时映射.从标准的POV来看,没有必要对QoI问题施加潜在的实施负担.

  • 方便程序员:根据您的方案,我们不必指定我们需要的标头.我们这样做是为了支持C++实现,这些实现选择实现将标准头文件整体化(当前就是所有这些)的想法,因此从C++标准的POV开始,这是"支持现有实践和程序员认为可接受的实施自由".哪种是C++的口号,不是吗?

由于没有C++实现(我知道)实际上这样做,我的怀疑是,事实上它并没有给你认为它带来的性能提升.Microsoft提供预编译头文件(via stdafx.h)正是出于性能原因,但它仍然没有为"所有标准库"提供选项,而是需要您说出您想要的内容.这对于此非常容易或者任何其他实现,以提供特定于实现的头,其被定义为具有与包括所有标准头相同的效果.这告诉我,至少在微软看来,提供这一点并没有太大的整体效益.

如果实现开始提供具有可证明的编译时性能改进的单片标准库,那么我们将讨论C++标准是否继续允许不实现的实现是一个好主意.事实上,它必须.

[*]除了可能<cassert>被定义为根据NDEBUG其包含的点的定义具有不同行为的事实.但我认为实现可以像往常一样预处理用户的代码,然后根据它是否定义在两个不同的表中映射.