C++ 为什么是“使用命名空间 std;” 被认为是不好的做法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1452721/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is "using namespace std;" considered bad practice?
提问by akbiggs
I've been told by others that writing using namespace std;
in code is wrong, and that I should use std::cout
and std::cin
directly instead.
其他人告诉我写using namespace std;
代码是错误的,我应该直接使用std::cout
和std::cin
代替。
Why is using namespace std;
considered a bad practice? Is it inefficient or does it risk declaring ambiguous variables (variables that share the same name as a function in std
namespace)? Does it impact performance?
为什么被using namespace std;
认为是不好的做法?它是低效的还是有风险声明不明确的变量(与std
命名空间中的函数同名的变量)?它会影响性能吗?
采纳答案by Greg Hewgill
This is not related to performance at all. But consider this: you are using two libraries called Foo and Bar:
这与性能完全无关。但请考虑一下:您正在使用两个名为 Foo 和 Bar 的库:
using namespace foo;
using namespace bar;
Everything works fine, and you can call Blah()
from Foo and Quux()
from Bar without problems. But one day you upgrade to a new version of Foo 2.0, which now offers a function called Quux()
. Now you've got a conflict: Both Foo 2.0 and Bar import Quux()
into your global namespace. This is going to take some effort to fix, especially if the function parameters happen to match.
一切正常,您可以毫无问题地Blah()
从 Foo 和Quux()
Bar调用。但是有一天你升级到 Foo 2.0 的新版本,它现在提供了一个名为Quux()
. 现在您遇到了冲突:Foo 2.0 和 Bar 都导入Quux()
到您的全局命名空间中。这将需要一些努力来修复,特别是如果函数参数碰巧匹配。
If you had used foo::Blah()
and bar::Quux()
, then the introduction of foo::Quux()
would have been a non-event.
如果您使用了foo::Blah()
和bar::Quux()
,那么 的引入foo::Quux()
将是一个非事件。
回答by sbi
I agree with everything Greg wrote, but I'd like to add: It can even get worse than Greg said!
我同意Greg 写的所有内容,但我想补充一点:它甚至可能比 Greg 说的更糟!
Library Foo 2.0 could introduce a function, Quux()
, that is an unambiguously better match for some of your calls to Quux()
than the bar::Quux()
your code called for years. Then your code still compiles, but it silently calls the wrong functionand does god-knows-what. That's about as bad as things can get.
库 Foo 2.0 可以引入一个函数,Quux()
,Quux()
与bar::Quux()
您多年来调用的代码相比,它无疑更适合您的某些调用。然后您的代码仍然可以编译,但它会默默地调用错误的函数并执行天知道是什么。这是最糟糕的事情。
Keep in mind that the std
namespace has tons of identifiers, many of which are verycommon ones (think list
, sort
, string
, iterator
, etc.) which are very likely to appear in other code, too.
请记住,在std
命名空间有万吨标识符,其中许多都是很常见的(想想list
,sort
,string
,iterator
,等),这是非常有可能出现在其他的代码了。
If you consider this unlikely: There was a question askedhere on Stack Overflow where pretty much exactly this happened (wrong function called due to omitted std::
prefix) about half a year after I gave this answer. Hereis another, more recent example of such a question.
So this is a real problem.
如果你认为这不太可能:在我给出这个答案大约半年后,Stack Overflow 上有一个问题在这里发生了(由于省略std::
前缀而调用了错误的函数)。这是此类问题的另一个最近的例子。所以这是一个真正的问题。
Here's one more data point: Many, many years ago, I also used to find it annoying having to prefix everything from the standard library with std::
. Then I worked in a project where it was decided at the start that both using
directives and declarations are banned except for function scopes. Guess what? It took most of us very few weeks to get used to writing the prefix, and after a few more weeks most of us even agreed that it actually made the code more readable. There's a reason for that: Whether you like shorter or longer prose is subjective, but the prefixes objectively add clarity to the code.Not only the compiler, but you, too, find it easier to see which identifier is referred to.
这里还有一个数据点:很多很多年前,我也曾经觉得必须在标准库中的所有内容前面加上std::
. 然后我在一个项目中工作,该项目一开始就决定using
除了函数作用域外,指令和声明都被禁止。你猜怎么着?我们大多数人花了几周的时间来习惯编写前缀,几周后我们大多数人甚至同意它实际上使代码更具可读性。这是有原因的:您喜欢更短还是更长的散文是主观的,但前缀客观地增加了代码的清晰度。不仅是编译器,您也可以更轻松地查看引用了哪个标识符。
In a decade, that project grew to have several million lines of code. Since these discussions come up again and again, I once was curious how often the (allowed) function-scope using
actually was used in the project. I grep'd the sources for it and only found one or two dozen places where it was used. To me this indicates that, once tried, developers don't find std::
painful enough to employ using directives even once every 100 kLoC even where it was allowed to be used.
十年后,该项目增长到有几百万行代码。由于这些讨论一再出现,我曾经很好奇(允许的)函数范围using
在项目中实际使用的频率。我搜索了它的来源,只找到了一两打使用它的地方。对我来说,这表明,一旦尝试过,std::
即使在允许使用的情况下,即使每 100 kLoC 使用一次 using 指令,开发人员也不会感到痛苦。
Bottom line: Explicitly prefixing everything doesn't do any harm, takes very little getting used to, and has objective advantages. In particular, it makes the code easier to interpret by the compiler and by human readers — and that should probably be the main goal when writing code.
底线:明确地为所有内容添加前缀不会造成任何伤害,几乎不需要习惯,并且具有客观优势。特别是,它使编译器和人类读者更容易解释代码——这可能是编写代码时的主要目标。
回答by ChrisW
The problem with putting using namespace
in the header files of your classes is that it forces anyone who wants to use your classes (by including your header files) to also be 'using' (i.e. seeing everything in) those other namespaces.
放入using namespace
类的头文件的问题在于它迫使任何想要使用您的类(通过包含您的头文件)的人也“使用”(即查看所有内容)其他命名空间。
However, you may feel free to put a using statement in your (private) *.cpp files.
但是,您可以随意在您的(私有)*.cpp 文件中放置 using 语句。
Beware that some people disagree with my saying "feel free" like this -- because although a using
statement in a cpp file is betterthan in a header (because it doesn't affect people who include your header file), they think it's still not good(because depending on the code it could make the implementation of the class more difficult to maintain). This C++ Super-FAQ entrysays,
请注意,有些人不同意我这样说“随意”——因为尽管using
cpp 文件中的语句比头文件中的语句要好(因为它不会影响包含您的头文件的人),但他们认为它仍然不是好(因为根据代码,它可能会使类的实现更难以维护)。这个 C++ Super-FAQ 条目说,
The using-directive exists for legacy C++ code and to ease the transition to namespaces, but you probably shouldn't use it on a regular basis, at least not in your new C++ code.
using-directive 存在于遗留 C++ 代码中并简化到命名空间的转换,但您可能不应该定期使用它,至少不在您的新 C++ 代码中使用它。
The FAQ suggests two alternatives:
常见问题解答提出了两种选择:
A using-declaration:
using std::cout; // a using-declaration lets you use cout without qualification cout << "Values:";
Just typing std::
std::cout << "Values:";
使用声明:
using std::cout; // a using-declaration lets you use cout without qualification cout << "Values:";
只需输入 std::
std::cout << "Values:";
回答by David Thornley
I recently ran into a complaint about Visual Studio 2010. It turned out that pretty much all the source files had these two lines:
我最近遇到了关于Visual Studio 2010的投诉。事实证明,几乎所有的源文件都有这两行:
using namespace std;
using namespace boost;
A lot of Boostfeatures are going into the C++0x standard, and Visual Studio 2010 has a lot of C++0x features, so suddenly these programs were not compiling.
很多Boost特性都进入了 C++0x 标准,而 Visual Studio 2010 有很多 C++0x 特性,所以突然这些程序无法编译。
Therefore, avoiding using namespace X;
is a form of future-proofing, a way of making sure a change to the libraries and/or header files in use is not going to break a program.
因此,避免using namespace X;
是一种面向未来的形式,一种确保对正在使用的库和/或头文件进行更改不会破坏程序的方法。
回答by mattnewport
Short version: don't use global using
declarations or directives in header files. Feel free to use them in implementation files. Here's what Herb Sutterand Andrei Alexandrescuhave to say about this issue in C++ Coding Standards(bolding for emphasis is mine):
简短版本:不要using
在头文件中使用全局声明或指令。随意在实现文件中使用它们。以下是Herb Sutter和Andrei Alexandrescu在C++ 编码标准中对这个问题的看法(粗体是我的):
Summary
Namespace usings are for your convenience, not for you to inflict on others: Never write a using declaration or a using directive before an #include directive.
Corollary: In header files, don't write namespace-level using directives or using declarations; instead, explicitly namespace-qualify all names. (The second rule follows from the first, because headers can never know what other header #includes might appear after them.)
Discussion
In short: You can and should use namespace using declarations and directives liberally in your implementation files after #include directives and feel good about it. Despite repeated assertions to the contrary, namespace using declarations and directives are not evil and they do not defeat the purpose of namespaces. Rather, they are what make namespaces usable.
概括
命名空间 using 是为了您的方便,而不是为了您对他人造成影响:永远不要在 #include 指令之前编写 using 声明或 using 指令。
推论:在头文件中,不要写命名空间级别的 using 指令或 using 声明;相反,明确命名空间限定所有名称。(第二条规则遵循第一条规则,因为标头永远无法知道其他标头 #includes 可能出现在它们之后。)
讨论
简而言之:在#include 指令之后,您可以并且应该在您的实现文件中自由地使用命名空间 using 声明和指令,并且对此感觉良好。尽管一再有相反的断言,使用命名空间的声明和指令并不是邪恶的,它们不会违背命名空间的目的。相反,它们使命名空间可用。
回答by robson3.14
One shouldn't use the using
directive at the global scope, especially in headers. However, there are situations where it is appropriate even in a header file:
不应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));
}
This is better than explicit qualification (std::sin
, std::cos
...), because it is shorter and has the ability to work with user defined floating point types (via argument-dependent lookup(ADL)).
这比显式限定 ( std::sin
, std::cos
...)更好,因为它更短并且能够处理用户定义的浮点类型(通过参数相关查找(ADL))。
回答by towi
Do not use it globally
不要全局使用
It is considered "bad" only when used globally. Because:
只有在全局使用时才被认为是“坏的” 。因为:
- You clutter the namespace you are programming in.
- Readers will have difficulty seeing where a particular identifier comes from, when you use many
using namespace xyz
. - Whatever is true for otherreaders of your source code is even more true for the most frequent reader of it: yourself. Come back in a year or two and take a look...
- If you only talk about
using namespace std
you might not be aware of all the stuff you grab -- and when you add another#include
or move to a new C++ revision you might get name conflicts you were not aware of.
- 你把你正在编程的命名空间弄得一团糟。
- 当您使用 many 时,读者将很难看到特定标识符的来源
using namespace xyz
。 - 对于源代码的其他读者而言,对于最常阅读源代码的人来说更是如此:您自己。一两年后回来看看...
- 如果你只谈论
using namespace std
你可能不知道你抓住的所有东西——当你添加另一个#include
或移动到一个新的 C++ 修订版时,你可能会遇到你不知道的名称冲突。
You may use it locally
你可以在本地使用
Go ahead and use it locally (almost) freely. This, of course, prevents you from repetition of std::
-- and repetition is also bad.
继续并在本地(几乎)自由地使用它。当然,这会阻止您重复std::
——而且重复也是不好的。
An idiom for using it locally
在本地使用它的习惯用法
In C++03 there was an idiom -- boilerplate code -- for implementing a swap
function for your classes. It was suggested that you actually use a local using namespace std
-- or at least using std::swap
:
在 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(...)`
}
This does the following magic:
这有以下魔法:
- The compiler will choose the
std::swap
forvalue_
, i.e.void std::swap(int, int)
. - If you have an overload
void swap(Child&, Child&)
implemented the compiler will choose it. - If you do nothave that overload the compiler will use
void std::swap(Child&,Child&)
and try its best swapping these.
- 编译器将选择
std::swap
forvalue_
,即void std::swap(int, int)
。 - 如果您
void swap(Child&, Child&)
实现了重载,编译器将选择它。 - 如果您没有那个重载,编译器将使用
void std::swap(Child&,Child&)
并尽力交换这些。
With C++11 there is no reason to use this pattern any more. The implementation of std::swap
was changed to find a potential overload and choose it.
有了 C++11,就没有理由再使用这种模式了。的实现std::swap
已更改以查找潜在的过载并选择它。
回答by sth
If you import the right header files you suddenly have names like hex
, left
, plus
or count
in your global scope. This might be surprising if you are not aware that std::
contains these names. If you also try to use these names locally it can lead to quite some confusion.
如果导入正确的头文件,你突然有名字,如hex
,left
,plus
或count
在全局范围内。如果您不知道std::
包含这些名称,这可能会令人惊讶。如果您还尝试在本地使用这些名称,则可能会导致相当多的混淆。
If all the standard stuff is in its own namespace you don't have to worry about name collisions with your code or other libraries.
如果所有标准内容都在其自己的命名空间中,您就不必担心与您的代码或其他库的名称冲突。
回答by Martin Beckett
Another reason is surprise.
另一个原因是惊喜。
If I see cout << blah
, instead of std::cout << blah
I think: What is this cout
? Is it the normal cout
? Is it something special?
如果我看到cout << blah
,而不是std::cout << blah
我想:这是什么cout
?这是正常的cout
吗?有什么特别的吗?
回答by Alexander Poluektov
Experienced programmers use whatever solves their problems and avoid whatever creates new problems, and they avoid header-file-level using-directives for this exact reason.
有经验的程序员使用任何解决他们问题的方法并避免任何产生新问题的方法,并且正是出于这个原因,他们避免使用头文件级 using 指令。
Experienced programmers also try to avoid full qualification of names inside their source files. A minor reason for this is that it's not elegant to write more code when less code is sufficient unless there are good reasons. A major reason for this is turning off argument-dependent lookup (ADL).
有经验的程序员也尽量避免在他们的源文件中完全限定名称。这样做的一个次要原因是,除非有充分的理由,否则在更少的代码就足够的情况下编写更多的代码并不优雅。一个主要原因是关闭参数相关查找 (ADL)。
What are these good reasons? Sometimes programmers explicitly want to turn off ADL, other times they want to disambiguate.
这些好的理由是什么?有时程序员明确地想关闭 ADL,有时他们想消除歧义。
So the following are OK:
所以以下是可以的:
- Function-level using-directives and using-declarations inside functions' implementations
- Source-file-level using-declarations inside source files
- (Sometimes) source-file-level using-directives
- 函数实现中的函数级 using 指令和 using 声明
- 源文件中的源文件级使用声明
- (有时)源文件级使用指令