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


当前回答

命名空间是为了避免命名冲突。C++基于C,C在函数和变量名方面有很多问题,因为有时来自不同库的函数会发生冲突。因此,库开发人员开始在其函数前面加上库名,如下所示:

foo/foo.h:

void libfoo_foo_foo_h_open(); // the name can be weird then even this one!

C++引入了名称空间,以一种简单的方式解决了这个问题。

假设您有两个名为file和window的库,分别处理文件和窗口,代码如下:

#include <file.h>
#include <window.h>

using namespace file;
using namespace window;

void open() {
     ...
}

文件.h:

namespace file {
    void open(); // What!
}

window.h:

namespace window {
    void open(); // Oh no!
}

上面的代码肯定无法编译。

如果你不喜欢键入std::(只有5个字符),你可以一直这样做:(在头文件中不是个好主意)

using s = std;

如果您仍然想使用名称空间std;在您的源文件中,那么您正在引发这个问题,我必须问您“NAMESPACE的目的是什么?”。

其他回答

这可能比Greg写的更糟!

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

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

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


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

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


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

很高兴看到代码并知道它做什么。如果我看到std::cout,我知道这是std库的cout流。如果我看到cout,我不知道。它可能是std库的cout流。或者有一个int cout=0;在同一函数中高出十行。或该文件中名为cout的静态变量。它可能是任何东西。

现在以一百万行代码库为例,它不是特别大,你正在搜索一个bug,这意味着你知道在这一百万行代码中有一行没有完成它应该做的事情;可以读取名为cout的静态int,将其向左移动一位,然后丢弃结果。要找bug,我必须检查一下。你能看出我真的更喜欢看std::cout吗?

如果你是一名教师,并且从未以编写和维护代码为生,那么这是一个非常好的主意。我喜欢看到代码:(1)我知道它做什么;而且,(2)我相信写它的人知道它的作用。

在类的头文件中使用名称空间的问题在于,它迫使任何想要使用您的类(通过包括头文件)的人也“使用”(即查看其他名称空间中的所有内容)。

但是,您可以随意在(私有)*.cpp文件中放入using语句。


请注意,有些人不同意我这样说的“感觉自由”,因为尽管cpp文件中的using语句比头文件中的要好(因为它不会影响包含头文件的人),但他们认为这仍然不好(因为根据代码的不同,这可能会使类的实现更难维护)。这个C++超级FAQ条目说,

using指令存在于遗留的C++代码中,用于简化向命名空间的转换,但您可能不应该定期使用它,至少不应该在新的C++代码。

常见问题解答建议了两种选择:

使用声明:使用std::cout;//using声明允许您无条件使用coutcout<<“值:”;只需键入std::std::cout<<“值:”;

有一个非常简单的答案:这是防御性编程。您知道,使用名称空间std;-可以使std::size_t、std::cout等的使用更容易一些我希望您不必相信这样的指令在标题中没有位置!然而,在翻译单元中,您可能会受到诱惑。。。

作为std命名空间一部分的类型、类等随着每次C++修订而增加。如果放松std::限定符,可能会有太多的歧义。放松std中经常使用的名称的限定符是完全合理的,例如,使用std::fprintf;,或者更可能的是:使用std::size_t;-但是,除非这些已经是语言的很好理解的部分(或者特别是C库的std包装),否则只使用限定符。

当您可以使用typedef并结合自动和decltype推理时,从可读性/可维护性的角度来看,实际上没有什么好处。

您需要能够阅读与您不同风格和最佳实践意见的人编写的代码。如果你只使用cout,没有人会感到困惑。但是,当你有很多名称空间到处飞的时候,你看到这个类,你不太确定它做什么时,让名称空间显式充当某种注释。您可以第一眼看到,“哦,这是一个文件系统操作”或“这是在做网络工作”。