我听说过使用名称空间std;这是不好的做法,我应该直接使用std::cout和std::cin。这是为什么?声明与std命名空间中的某个变量同名的变量是否有风险?


当前回答

这可能比Greg写的更糟!

Library Foo 2.0可能会引入一个函数Qux(),它无疑比多年来代码调用的bar::Qux)更适合您对Qux的某些调用。然后你的代码仍然可以编译,但它会默默地调用错误的函数,上帝知道会发生什么。这是最糟糕的事情了。

请记住,std名称空间有大量的标识符,其中许多是非常常见的标识符(例如列表、排序、字符串、迭代器等),这些标识符也很可能出现在其他代码中。

如果你认为这不太可能:在我给出这个答案大约半年后,在Stack Overflow上有一个问题(由于省略了std::前缀而调用了错误的函数)。这是这一问题的另一个最近的例子。所以这是一个真正的问题。


这里还有一个数据点:很多很多年前,我还发现必须在标准库中的所有内容前面加上std::,这很烦人。然后我在一个项目中工作,一开始就决定禁止使用指令和声明,但函数作用域除外。猜猜怎么了?我们中的大多数人花了几周的时间才习惯写前缀,再过几周,我们中的大部分人甚至同意这实际上使代码更可读。这是有原因的:你喜欢较短或较长的散文是主观的,但前缀客观上增加了代码的清晰度。不仅是编译器,您也会发现更容易看到引用的是哪个标识符。

在十年内,该项目发展到拥有数百万行代码。由于这些讨论一次又一次出现,我一度很好奇项目中实际使用(允许)函数范围的频率。我查阅了它的来源,只找到了一两打使用它的地方。对我来说,这表明,一旦尝试过,即使在允许使用std::的地方,开发人员也不会觉得每100kLoC使用一次指令就足够痛苦。


一句话:明确地给每件事加上前缀不会造成任何伤害,只需要很少的时间就可以习惯,而且有客观的优势。特别是,它使编译器和人类读者更容易解释代码,这可能是编写代码时的主要目标。

其他回答

我认为本地或全球使用应取决于应用程序。

因为,当我们在本地使用库时,有时代码会变得一团糟。可读性将下降。

因此,只有在可能发生冲突时,我们才应该在本地使用库。

我不是一个更有经验的人。所以,如果我错了,请告诉我。

考虑

// myHeader.h
#include <sstream>
using namespace std;


// someoneElses.cpp/h
#include "myHeader.h"

class stringstream {  // Uh oh
};

请注意,这是一个简单的示例。如果您有包含20个include和其他导入的文件,那么您将有大量的依赖项来解决问题。更糟糕的是,根据冲突的定义,在其他模块中可能会出现不相关的错误。

这并不可怕,但如果不在头文件或全局名称空间中使用它,您将省去麻烦。在非常有限的范围内执行它可能是正确的,但我从未遇到过键入额外的五个字符来澄清我的函数来自何处的问题。

另一个原因是惊讶。

如果我看到cout<<blah,而不是std::cout<<blah,我会想:这是什么cout?这是正常的服装吗?有什么特别的吗?

这是个案。我们希望在软件的生命周期内最大限度地降低软件的“总拥有成本”。声明“using namespace std”有一定的代价,但不使用它也有易读性的代价。

人们正确地指出,当使用它时,当标准库引入新的符号和定义时,您的代码将停止编译,您可能被迫重命名变量。然而,这可能是一个很好的长期目标,因为如果您出于某种令人惊讶的目的使用关键字,未来的维护人员将暂时感到困惑或分心。

你不希望有一个名为vector的模板,比如说,它不是其他人都知道的向量。因此,C++库中引入的新定义的数量非常少,可能根本找不到。必须进行这种更改是有代价的,但代价并不高,而且通过不将std符号名称用于其他目的而获得的清晰性来抵消。

考虑到类、变量和函数的数量,在每一个上声明std::可能会使代码出错50%,并使您更难理解。一个算法或方法中的一个步骤可以在一屏代码上执行,现在需要前后滚动才能执行。这是一个真实的成本。可以说,这可能不是一个高成本,但那些否认它存在的人是缺乏经验的、教条的,或者根本就是错误的。

我提供以下规则:

std不同于所有其他库。这是每个人基本上都需要知道的一个库,在我看来,最好将其视为语言的一部分。一般来说,使用命名空间std是一个很好的例子,即使没有其他库。永远不要通过将此using放在头中来迫使编译单元(.cpp文件)的作者做出决定。始终将决定权交给编译单元的作者。即使在一个决定在任何地方使用名称空间std的项目中,也可能会有一些模块作为该规则的例外处理。尽管名称空间功能允许您有许多定义相同符号的模块,但这样做会令人困惑。请尽可能保持名称不同。即使不使用名称空间特性,如果您有一个名为foo的类,并且std引入了一个名foo的类型,那么长期来说重命名您的类可能会更好。使用名称空间的另一种方法是通过前缀手动命名符号。我有两个库,我用了几十年,实际上都是从C库开始的,每个符号的前缀都是“AK”或“SCWin”。一般来说,这就像避免使用“using”构造,但不使用双冒号。AK::foo()改为AKFoo()。它使代码更密集5-10%,更不冗长,唯一的缺点是,如果必须使用两个具有相同前缀的这样的库,则会遇到很大的麻烦。注意,X Window库在这方面非常出色,只是它们忘记了使用一些#定义:TRUE和FALSE应该是XTRUE和XFALSE,这与Sybase或Oracle产生了命名空间冲突,它们同样使用了TRUE和FALSE,但值不同!(在数据库的情况下为ASCII 0和1!)这样做的一个特殊优点是,它似乎适用于预处理器定义,而C++使用/命名空间系统不处理它们。这样做的一个好处是,它提供了从项目的一部分到最终成为图书馆的有机坡度。在我的一个大型应用程序中,所有的窗口类都以Win为前缀,所有的信号处理模块都以Mod为前缀等等。这些模块中的任何一个都不太可能被重用,因此将每个组放入一个库中没有实际的好处,但几秒钟后就可以看出项目是如何分解为子项目的。

老实说,对我来说,这就像讨论缩进空间的数量。

在标头中使用指令会导致损坏。但是在C++文件中呢?如果同时使用两个名称空间,可能会发生这种情况。但如果你使用一个,它更多的是风格而不是真正的效率。

你知道为什么关于缩进的线索如此流行吗?任何人都可以说些什么,听起来非常聪明和有经验。