我听说过使用名称空间std;这是不好的做法,我应该直接使用std::cout和std::cin。这是为什么?声明与std命名空间中的某个变量同名的变量是否有风险?
当前回答
不要全局使用它
只有在全球范围内使用时,它才被认为是“坏的”。因为:
你把正在编程的命名空间弄得乱七八糟。当您使用许多名称空间xyz;时,读者将很难看到特定标识符的来源;。无论对你的源代码的其他读者来说是什么,对最经常阅读源代码的读者来说更是如此:你自己。一两年后回来看看。。。如果您只讨论使用名称空间std;你可能不知道你抓取的所有内容——当你添加另一个#include或移动到一个新的C++修订版时,你可能会遇到你不知道的名称冲突。
您可以在本地使用
继续,在本地(几乎)自由使用它。当然,这可以防止你重复std::--,重复也是不好的。
本地使用它的习惯用法
在C++03中,有一种习惯用法——样板代码——用于为类实现交换函数。有人建议您实际使用本地using命名空间std;--或至少使用std::swap;:
class Thing {
int value_;
Child child_;
public:
// ...
friend void swap(Thing &a, Thing &b);
};
void swap(Thing &a, Thing &b) {
using namespace std; // make `std::swap` available
// swap all members
swap(a.value_, b.value_); // `std::stwap(int, int)`
swap(a.child_, b.child_); // `swap(Child&,Child&)` or `std::swap(...)`
}
这有以下魔力:
编译器将为value_选择std::swap,即void std::swap(int,int)。如果实现了重载void swap(Child&,Child&),编译器将选择它。如果没有重载,编译器将使用void std::swap(Child&,Child&),并尽可能地交换这些。
对于C++11,没有理由再使用这种模式了。对std::swap的实现进行了更改,以找到一个潜在的过载并选择它。
其他回答
为了回答你的问题,我实际上是这样看的:很多程序员(不是所有人)都调用命名空间std。因此,人们应该养成习惯,不要使用与命名空间std中的名称冲突或使用相同名称的东西。这是一个很大的事实,但与严格来说可能出现的连贯单词和假名的数量相比,这并不是那么多。
我是说真的。。。说“不要依赖于这个存在”只是让你依赖于它不存在。您经常会遇到借用代码片段并不断修复它们的问题。只需将用户定义的和借用的内容保持在有限的范围内,并且非常节省全局变量(老实说,全局变量几乎永远是“现在编译,以后理智”的最后手段)。我真的认为这是你老师的坏建议,因为使用std对“cout”和“std::cout”都有效,但不使用std只对“std:”cout有效。你不会总是幸运地编写自己的代码。
注意:在真正了解编译器的工作原理之前,不要过于关注效率问题。只要有一点编码经验,在你意识到他们能够将好的代码概括成简单的东西之前,你不必了解他们太多。每一点都很简单,就像你用C语言写了整件事一样。
考虑两个名为Foo和Bar的库:
using namespace foo;
using namespace bar;
一切都很好,你可以从Foo调用Blah(),从Bar调用Qux()。但有一天你升级到了Foo 2.0的新版本,它现在提供了一个名为Qux()的函数。现在出现了一个冲突:Foo 2.0和Bar都将Qux()导入到全局命名空间中。这将需要一些努力来解决,特别是如果函数参数恰好匹配。
如果您使用了foo::Blah()和bar::Qux(),那么引入foo::Qux()将是一个非事件。
这是个案。我们希望在软件的生命周期内最大限度地降低软件的“总拥有成本”。声明“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为前缀等等。这些模块中的任何一个都不太可能被重用,因此将每个组放入一个库中没有实际的好处,但几秒钟后就可以看出项目是如何分解为子项目的。
另一个原因是惊讶。
如果我看到cout<<blah,而不是std::cout<<blah,我会想:这是什么cout?这是正常的服装吗?有什么特别的吗?
一个例子是,使用名称空间std会因为计数的模糊性而引发编译错误,这也是算法库中的一个函数。
#include <iostream>
#include <algorithm>
using namespace std;
int count = 1;
int main() {
cout << count << endl;
}