namespaces - “using namespace std;”为什么被认为是糟糕的做法?

  显示原文与译文双语对照的内容

许多人在很多场合都告诉我,我的老师说我们应该在程序中使用 using namespace std;因此,我们应该使用 std::coutstd::cin 和这些更合适。 然而,他们甚至不清楚为什么这是一个不好的实践。

为什么 using namespace std; 认为不正确? 它确实是低效的,还是风险不明确的vars(variables that share the same name as a function in std namespace)? 或者当你编写更大的应用程序时,这种影响会显著影响程序性能?

时间:

这与性能根本不相关。 但是考虑一下:你正在使用两个库,称为Foo和 Bar:


using namespace foo;
using namespace bar;

一切正常,你可以从 Blah()Quux() 调用,而没有问题。 但是有一天你升级到新版本的foo 2.0,现在提供了一个名为 Quux()的函数。 现在你遇到了一个冲突: Foo 2.0和酒吧 Quux() 导入到全局名称空间。 这将需要一些努力来修复,特别是如果函数参数恰好匹配。

如果你使用了 foo::Blah()bar::Quux(),那么 foo::Quux()的引入将是一个 non-event 。

我同意所有编写的 。xml,但我想添加: 比格雷格说,它甚至可以变得越来越糟

图书馆foo 2.0可能介绍函数Quux()明确更好匹配一些调用代码比 bar::Quux()Quux() 呼吁多年。 仍然那么你代码编译,但默默地调用错误的函数和 god-knows-what 。 这就跟你所能得到的一样。

记住, std 命名空间有很多标识符,其中许多非常常见的( 思考 listsortstringiterator 等等 ) 很可能出现在其他代码,。

如果你认为这不太可能: 有问题问 在哪里几乎完全发生( 由于省略的std:: 前缀,调用了错误的函数) 大约半年后我给了这个答案。 这里 是另一个,最近例子这样的一个问题。
所以这是一个真正的问题


这里还有一个数据点: 许多年前,我也曾经发现有与 std:: 前缀从标准库。 然后我在一个项目中工作,它决定了 using 指令和声明都被禁止,除了函数作用域之外。 你猜怎么着?我们大多数人花了很几周去用来写前缀。几周之后,我们大多数人甚至认为它实际上使代码更具可读性。 ( 有一个原因: 不管你喜欢短或更长时间散文是主观的,但客观清晰的代码添加前缀。 不仅编译器,但你,也更容易看到标识符被称为。)

在十年内,那个项目增长了几百万行代码。 由于这些讨论反复出现,我曾经好奇( 允许的) function-scope using 在项目中的使用频率。 grep拥有它的源,只找到了一个或者两个使用它的地方。 对我来说,这表明,一旦尝试,开发人员没有发现 std:: 痛苦足够雇佣使用指令甚至一次 100代码甚至允许使用。


底线:显式地前缀所有内容不会造成任何损害,需要很少的使用,并且有客观优势。 特别是,它使得编译器和读者的—更容易理解代码,这可能是编写代码时的主要目标。

我最近遇到了关于 vs 2010的投诉。 结果几乎所有的源文件都有这两行:


using namespace std;
using namespace boost;

C++0x标准中有很多增强特性,并且VS2010有很多C++0x特性,所以突然这些程序没有编译。

因此,避免 using namespace X; 是future-proofing的一种形式,这是确保对库和/或者头文件所做的更改不会破坏程序的一种方式。

在全局作用域中不应使用指令,尤其在标头中。 但是,在某些情况下,即使在头文件中也是合适


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 也好- ) 好,因为它较短,并且能够处理用户定义的浮点类型( 通过参数从属查找) 。

如果你导入正确的头文件突然有名字像 hex, left, pluscount 全局作用域。 如果你不知道 std:: 包含这些名称,这可能会令人吃惊。 如果你在本地使用这些名字,它可能会引起一些混乱。

如果所有标准内容都在它自己的命名空间中,你就不必担心名称冲突与代码或者其他库。

不要全局使用它

它被认为只有当 "错误"全球使用。 因为

  • 你正在编写的命名空间混乱。
  • 当你使用许多 using namespace xyz 时,读者很难看到特定标识符来自哪里。
  • 其他任何适用于源代码的读者是最频繁的读者来说,情况更是如此: 你自己。请在一年后再回来看看。
  • 如果你只谈论 using namespace std 你可能不知道的所有东西你抓住--当你添加另一个 #include 或搬到一个新的C++-revision你可能会得到你没有意识到的名称冲突

你可以在本地使用它

继续并在本地使用( 几乎几乎) 。 这当然会阻止你重复 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(...)`
}

这样做的魔力如下

  • 编译器将选择 value_std::swap,换句话说,void std::swap(int, int)
  • 如果你有一个重载 void swap(Child&, Child&) 实现编译器将选择它
  • 如果你做了 ,编译器将使用 void std::swap(Child&,Child&) 并尝试它的最佳交换。

使用 C++11,没有理由再使用这种模式。 std::swap的实现被更改为寻找潜在的重载并选择它。

我也认为这是一个不好的做法。 为什么只有一天我认为名称空间的功能是分开的,所以我不会把东西扔到一个全局包中。 但是,如果我经常使用'cout'和'cin',我将编写: using std::cout; using std::cin; 在cpp文件( 从不在头文件中传播,因为它用 #include 传播) 中。 我认为谁都不会理智地命名 cout 或者 cin 。 ; )

...