http://*.com/questions/5849457/using-namespace-in-c-headers
http://*.com/questions/5849457/using-namespace-in-c-headers 這篇有解釋 避免在 header用 using namespace, 以免header被其他人include後 造成Conflict
n all our c++ courses, all the teachers always put using namespace std;
right after the #include
s in their .h
files. This seems to me to be dangerous since then by including that header in another program I will get the namespace imported into my program, maybe without realizing, intending or wanting it (header inclusion can be very deeply nested).
So my question is double: Am I right that using namespace
should not be used in header files, and/or is there some way to undo it, something like:
//header.h
using namespace std {
.
.
.
}
One more question along the same lines: Should a header file #include
all the headers that it's corresponding .cpp
file needs, only those that are needed for the header definitions and let the .cpp
file #include
the rest, or none and declare everything it needs as extern
?
The reasoning behind the question is the same as above: I don't want surprises when including .h
files.
Also, if I am right, is this a common mistake? I mean in real-world programming and in "real" projects out there.
Thank you.
You should definitely NOT use using namespace
in headers
for precisely the reason you say, that it can unexpectedly change the
meaning of code in any other files that include that header. There's no
way to undo a using namespace
which is another reason it's so dangerous. I typically just use grep
or the like to make sure that using namespace
isn't being called out in headers rather than trying anything more complicated. Probably static code checkers flag this too.
The header should include just the headers that it needs to compile.
An easy way to enforce this is to always include each source file's own
header as the first thing, before any other headers. Then the source
file will fail to compile if the header isn't self-contained. In some
cases, for example referring to implementation-detail classes within a
library, you can use forward declarations instead of #include
because you have full control over the definition of such forward declared class.
I'm not sure I would call it common, but it definitely shows up once
in a while, usually written by new programmers that aren't aware of the
negative consequences. Typically just a little education about the
risks takes care of any issues since it's relatively simple to fix.
原文:I don’t want to see another “using namespace xxx;” in a header file ever again
在这里,我毫不回避地说了这句话。
作为一个开发者/团队领导者,我经常会去招聘新的项目成员,有时候也帮助其他组的人来面试应聘者。作为应聘流程之一,我经常要求应聘者 写一些代码,因此我检查过相当多的代码。在最近提交的 C++ 代码中,我注意到一个趋势,在任何头文件中,我总是能看到以下代 码:
using namespace std;
如果我用我们的代码检查系统(在实践中我十分推荐这个系统)来检验代码,以上那行代码经常会跟着一句评论“Timo 不会这样写的”。他们说得很对,我确实不会这么写。
那么,为什么我说服了很多 C++ 教材(也许并不是什么好事),让他们认为使用上面那段代码是非常坏的方式?让我们先来看看上面那段代码做了什么。总的来说,它把命名空间“std”以内的 所有内容(或者其他由作者用 using 调用命名空间)无一例外的引入了目前的命名空间中。请注意我说的“所有内容”,并不是一两个你想用的类\类型\模板。在一段代码的开头引入命 名空间的原因 则是加强程序模块化,和减少命名冲突。大体上,它允许你可以写类似下面的那段代码,并且保证编译器可以选择正确的实现:
std::vector<std::string> names;
my_cool_reimplementation::vector<our_internal_stuff::string> othernames;
现在,假定我们正在尝试减少代码输入,并且在以上代码中使用 using 声明(或者更糟糕的,两个命名空间都声明了),按照如下代码来实现:
vector<string> names;
vector<our_internal_stuff::string> othernames;
如果这段代码的作者很幸运的话,编译器会选择 vector 的正确实现,或者至少在最初的阶段会这么做。但是过了一段时间,你会碰到一些很奇怪的编译器错误。幸运的话,你能找到这些错误的原因——我曾经遇到过类似 问题,我花费了好几天才能找到这类问题的原因。该死,它们会浪费你很多的时间,仅仅因为你为了想少打 5 个字符的代码。
并且,如果你把 using 声明用在了头文件中,你会让这 类问题更加恶化,因为命名冲突问题早晚都会在一个调用关系非常非常远的模块中神不知鬼不觉的出现,而你可能需要查三层调用才可以找到原因所 在,一个头文件包含了另一个直 接使用 using 声明的头文件可以导致命名空间被立刻污 染掉,任何一个使用命名空间的文件如果使用了 std 命名空间的内容,都会导致这类问题。
那么,为什么你能在很多教科书中看到它们使用 using namespace std?我的理论是,它确实会帮助改善整本书的排版,并且能减少一些视觉的混乱。在一本纸质书中,你只有很有限的空间来写文字,因此你必须最大限度的利用 它,加之书中的代码例子通常都很简单。但另一方面,不同的命名空间限定符会带来了很多视觉混乱,这会让读者很难从上下文判断作者的意图。当你 想在这个时代 写一些有效率的代码的时候,以上两点都不完全对,现在的编译器大多数能每行处理 60-80 个单词(你可以试试,这可以的)。因此,不要乱引入命名空间。
如果你非常明确的想在一个头文件中 使用 using 声明,应该怎么做?我们有其他途径可以减少不得不用 using 声明的情况——你可以用以下其中一种,或则多种方式的组合。
首先,你只需使用 typedef。我会建议你使用这种方法,即使我并不经常遵循我自己的建议,我也认为无论如何这都是一个在实际应用中很好的方法。实际上,使用 typedef 有两个好处——他让一个类型名可读性增加,如果你选择了一个很好的名字,它可以让作者的意图更加显而易见。比较一下如下的声明方式:
std::map<std::string, long> clientLocations;
typedef std::map<std::string, long> ClientNameToZip;
ClientNameToZip clientLocations;
第二个声明——即使它被展开为两行——也比第一个声明更加直观,同时,它也避免了命名空间模糊化。
另外一个选择则是用两种方法来限制 using 声明的作用域——仅仅是你想用的那个“using” 符号,例如:
using std::string;
但是,把这段声明扔到头文件中, 几乎和使用“using namespace”一样糟糕, 因此,你应该使用作用域来限制下它的可见性,来确保你的 using 声明真的只在第一次做 using 声明的地方有效。例如,你可以用如下方法限制类声明作用域:
namespace bar
{
struct zzz
{
…
};
}
class foo
{
using namespace bar;
zzz m_snooze; // Pulls in bar::zzz };
或者,你可以直接把 using 的作用域限制到一个函数中,例如:
void temp ()
{
using namespace std;
string test = "fooBar";
}
不管哪种方法,你都可以把 using 的作用域限制到需要使用它的代码中,而不是把它放到代码的公共空间中。你的工程越大,确保模块化,和最小化不可预料的负面影响就显得越发重 要。