其他人告诉我写作 using namespace std
在代码中是错误的,我应该使用 std::cout
和 std::cin
直接代替。
为什么是 using namespace std
被认为是不好的做法?它是否效率低或是否有风险声明模糊变量(变量与函数中的函数同名) std
命名空间)?它会影响性能吗?
其他人告诉我写作 using namespace std
在代码中是错误的,我应该使用 std::cout
和 std::cin
直接代替。
为什么是 using namespace std
被认为是不好的做法?它是否效率低或是否有风险声明模糊变量(变量与函数中的函数同名) std
命名空间)?它会影响性能吗?
这根本与性能无关。但请考虑一下:您正在使用两个名为Foo和Bar的库:
using namespace foo;
using namespace bar;
一切正常,你可以打电话 Blah()
来自Foo和 Quux()
从酒吧没有问题。但是有一天你升级到新版本的Foo 2.0,它现在提供了一个名为的功能 Quux()
。现在你有一个冲突:Foo 2.0和Bar导入 Quux()
进入全局命名空间。这将需要一些努力来修复,特别是如果函数参数碰巧匹配。
如果你曾经使用过 foo::Blah()
和 bar::Quux()
,然后介绍 foo::Quux()
本来不是一件事。
我同意一切 格雷格写道,但我想补充一下: 它甚至可能比格雷格说的更糟糕!
Library Foo 2.0可以引入一个函数, Quux()
,这是一些明确更好的匹配你的一些电话 Quux()
比 bar::Quux()
你的代码要求多年。然后你的 代码仍然编译但是 它默默地调用错误的函数 上帝知道什么。事情就像事情一样糟糕。
请记住 std
namespace有很多标识符,其中很多都是 非常 常见的(想想 list
, sort
, string
, iterator
等等,也很可能出现在其他代码中。
如果你认为这不太可能:有 一个问题 这里发生了Stack Overflow,其中恰好发生了这种情况(由于省略了错误的函数) std::
在我给出这个答案后大约半年。 这里 是这个问题的另一个最近的例子。
所以这是一个真正的问题。
这里还有一个数据点:很多年前,我还常常发现它必须为标准库中的所有内容添加前缀 std::
。然后我在一个项目中工作,一开始就决定两者 using
除函数范围外,禁止使用指令和声明。你猜怎么了?我们大部分时间都花了很长时间才习惯编写前缀,经过几周之后,我们大多数人甚至同意它实际上已经编写了代码 更具可读性。这是有原因的: 无论你喜欢更短或更长的散文是主观的,但前缀客观上增加了代码的清晰度。 不仅是编译器,而且您也发现更容易看到引用了哪个标识符。
十年来,该项目增长了数百万行代码。由于这些讨论一次又一次地出现,我曾经很好奇(允许的)功能范围 using
实际上是在项目中使用的。我找到它的来源,只找到了一两个地方使用它。对我而言,这表明,一旦尝试过,开发人员就找不到了 std::
即使在允许使用指令的情况下,即使每100kLoC使用指令也足够痛苦。
底线:明确地为所有内容添加前缀不会造成任何伤害,很少习惯,并具有客观优势。特别是,它使编码器和人类读者更容易理解代码 - 这应该是编写代码时的主要目标。
我认为把它放在你的类的头文件中是很糟糕的:因为那样你就会强迫任何想要使用你的类(通过包含你的头文件)也可以'使用'(即看到所有内容)这些其他命名空间。
但是,您可以随意在(私有)* .cpp文件中放置using语句。
请注意,有些人不同意我的说法“感觉自由”,因为尽管cpp文件中的using语句是 更好 而不是在标题中(因为它不会影响包含您的头文件的人),他们认为它仍然没有 好 (因为根据代码,它可能使类的实现更难维护)。 这个FAQ主题 说,
using-directive存在于遗留C ++代码中,并且可以简化向命名空间的转换,但您可能不应该定期使用它,至少不应该在新的C ++代码中使用它。
它提出了两种选择:
使用声明:
using std::cout; // a using-declaration lets you use cout without qualification
cout << "Values:";
克服它,只需键入std ::
std::cout << "Values:";
我最近遇到了一个投诉 Visual Studio 2010中。事实证明,几乎所有源文件都有这两行:
using namespace std;
using namespace boost;
许多 促进 功能进入C ++ 0x标准,Visual Studio 2010有很多C ++ 0x功能,所以突然这些程序没有编译。
因此,避免 using namespace X;
是一种面向未来的形式,一种确保对正在使用的库和/或头文件的更改不会破坏程序的方法。
简短版本:不要在头文件中使用全局使用声明或指令。随意在实现文件中使用它们。以下是Herb Sutter和Andrei Alexandrescu对此问题的评论 C ++编码标准 (重点强调是我的):
概要
命名空间使用是为了您的方便,而不是让您对其他人造成:在#include指令之前,切勿编写using声明或using指令。
推论:在头文件中,不要使用指令或使用声明来编写命名空间级别;相反,显式命名空间限定所有名称。 (第二条规则从第一条开始,因为标题永远不会知道其他标题#includes可能会出现在它们之后。)
讨论
简而言之:在#include指令之后,你可以而且应该在你的实现文件中使用声明和指令来使用命名空间,并且感觉良好。 尽管反复断言,使用声明和指令的命名空间并不是邪恶的,并且它们不会破坏命名空间的目的。相反,它们是使命名空间可用的原因。
不应该在全局范围内使用using指令,尤其是在头文件中。但是,即使在头文件中也存在适当的情况:
template <typename FloatType> inline
FloatType compute_something(FloatType x)
{
using namespace std; //no problem since scope is limited
return exp(x) * (sin(x) - cos(x * 2) + sin(x * 3) - cos(x * 4));
}
这比明确的资格要好(std::sin
, std::cos
...)
因为它更短并且能够使用用户定义的浮点类型(通过Argument Dependent Lookup)。
只有当它被认为是“坏”时 全球使用。因为:
using namespace xyz
。using namespace std
你可能没有意识到你抓住的所有东西 - 当你添加另一个东西时 #include
或者转到新的C ++版本,你可能会得到你不知道的名称冲突。继续在本地(几乎)自由使用它。当然,这可以防止你重复 std::
- 重复也很糟糕。
在C ++ 03中有一个成语 - 样板代码 - 用于实现 swap
你的课程的功能。有人建议你实际使用本地 using namespace std
- 或者至少 using 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(...)`
}
这有以下魔力:
std::swap
对于 value_
,即 void std::swap(int, int)
。void swap(Child&, Child&)
实现编译器会选择它。void std::swap(Child&,Child&)
并尝试最好地交换这些。使用C ++ 11,没有理由再使用这种模式。实施 std::swap
被改为发现潜在的超载并选择它。