我听说过使用名称空间std;这是不好的做法,我应该直接使用std::cout和std::cin。这是为什么?声明与std命名空间中的某个变量同名的变量是否有风险?
当前回答
命名空间是命名作用域。命名空间用于对相关声明进行分组并保持独立项目分开。例如,两个单独开发的库可以使用相同的名称来表示不同的项,但用户仍然可以同时使用这两个:
namespace Mylib{
template<class T> class Stack{ /* ... */ };
// ...
}
namespace Yourlib{
class Stack{ /* ... */ };
// ...
}
void f(int max) {
Mylib::Stack<int> s1(max); // Use my stack
Yourlib::Stack s2(max); // Use your stack
// ...
}
重复名称空间名称可能会分散读者和作者的注意力。因此,有可能声明来自特定命名空间的名称在没有明确限定的情况下可用。例如:
void f(int max) {
using namespace Mylib; // Make names from Mylib accessible
Stack<int> s1(max); // Use my stack
Yourlib::Stack s2(max); // Use your stack
// ...
}
命名空间为管理不同库和不同版本的代码提供了强大的工具。特别是,它们为程序员提供了如何明确引用非本地名称的备选方案。
来源:C++编程语言概述作者:Bjarne Stroustrup
其他回答
这可能比Greg写的更糟!
Library Foo 2.0可能会引入一个函数Qux(),它无疑比多年来代码调用的bar::Qux)更适合您对Qux的某些调用。然后你的代码仍然可以编译,但它会默默地调用错误的函数,上帝知道会发生什么。这是最糟糕的事情了。
请记住,std名称空间有大量的标识符,其中许多是非常常见的标识符(例如列表、排序、字符串、迭代器等),这些标识符也很可能出现在其他代码中。
如果你认为这不太可能:在我给出这个答案大约半年后,在Stack Overflow上有一个问题(由于省略了std::前缀而调用了错误的函数)。这是这一问题的另一个最近的例子。所以这是一个真正的问题。
这里还有一个数据点:很多很多年前,我还发现必须在标准库中的所有内容前面加上std::,这很烦人。然后我在一个项目中工作,一开始就决定禁止使用指令和声明,但函数作用域除外。猜猜怎么了?我们中的大多数人花了几周的时间才习惯写前缀,再过几周,我们中的大部分人甚至同意这实际上使代码更可读。这是有原因的:你喜欢较短或较长的散文是主观的,但前缀客观上增加了代码的清晰度。不仅是编译器,您也会发现更容易看到引用的是哪个标识符。
在十年内,该项目发展到拥有数百万行代码。由于这些讨论一次又一次出现,我一度很好奇项目中实际使用(允许)函数范围的频率。我查阅了它的来源,只找到了一两打使用它的地方。对我来说,这表明,一旦尝试过,即使在允许使用std::的地方,开发人员也不会觉得每100kLoC使用一次指令就足够痛苦。
一句话:明确地给每件事加上前缀不会造成任何伤害,只需要很少的时间就可以习惯,而且有客观的优势。特别是,它使编译器和人类读者更容易解释代码,这可能是编写代码时的主要目标。
另一个原因是惊讶。
如果我看到cout<<blah,而不是std::cout<<blah,我会想:这是什么cout?这是正常的服装吗?有什么特别的吗?
一个具体的例子来澄清这个问题。假设您有两个库,foo和bar,每个库都有自己的名称空间:
namespace foo {
void a(float) { /* Does something */ }
}
namespace bar {
...
}
现在假设您在自己的程序中同时使用foo和bar,如下所示:
using namespace foo;
using namespace bar;
void main() {
a(42);
}
现在一切都很好。当你运行程序时,它会“做一些事情”。但后来你更新了这个栏,让我们假设它变成了这样:
namespace bar {
void a(float) { /* Does something completely different */ }
}
此时将出现编译器错误:
using namespace foo;
using namespace bar;
void main() {
a(42); // error: call to 'a' is ambiguous, should be foo::a(42)
}
因此,您需要进行一些维护,以澄清“a”是指foo::a。这是不可取的,但幸运的是它非常容易(只需在编译器标记为不明确的所有调用前面添加foo::)。
但想象一下另一种情况,酒吧改成了这样:
namespace bar {
void a(int) { /* Does something completely different */ }
}
此时,您对a(42)的调用突然绑定到bar::a而不是foo::a,并且它不做“某事”,而是做“完全不同的事情”。没有编译器警告或任何内容。你的程序只是默默地开始做一些与以前完全不同的事情。
当你使用一个名称空间时,你会面临这样的风险,这就是为什么人们不喜欢使用名称空间的原因。名称空间中的东西越多,冲突的风险就越大,因此与其他名称空间相比,人们可能更不喜欢使用名称空间std(由于该名称空间中有很多东西)。
最终,这是可写性与可靠性/可维护性之间的权衡。可读性也可能是其中的一个因素,但无论哪种方式,我都能看到这样做的理由。通常,我会说可靠性和可维护性更重要,但在这种情况下,您将不断为相当罕见的可靠性/可维护性影响支付可写性成本。“最佳”权衡将决定您的项目和优先级。
我也认为这是一种糟糕的做法。为什么?就在一天,我认为名称空间的功能是划分内容,所以我不应该将所有内容都放在一个全局包中而破坏它。
然而,如果我经常使用“cout”和“cin”,我会写:使用std::cout;使用std::cin;在.cpp文件中(当它使用include传播时,不会在头文件中)。我想,没有一个理智的人会说出一条小溪的名字
“为什么在C++中‘使用命名空间std;’被认为是一种糟糕的做法?”
我反过来说:为什么有些人认为额外键入五个字符很麻烦?
例如,考虑编写一个数字软件。当“vector”是问题领域最重要的概念之一时,我为什么还要考虑将通用的“std::vector”缩减为“vector”来污染我的全局命名空间?