“使用命名空间”在 c++标头
在我们所有的 C++ 课程中,所有老师总是将 using namespace std;
放在 .h
文件中的 #include
之后。在我看来,这似乎很危险,因为通过在另一个程序中包含该标头,我会将名称空间导入到我的程序中,也许没有意识到、打算或想要它(标头包含可以非常深入地嵌套)。
所以我的问题是双重的:我是否正确地认为 using namespace
不应在头文件中使用,和/或是否有某种方法可以撤消它,例如:
//header.h
using namespace std {
.
.
.
}
还有一个同样的问题:应该头文件 #include
其对应的 .cpp
文件需要的所有头文件,仅包含那些头定义所需的头文件,并让 .cpp
> 文件 #include
其余部分,或无并将其需要的所有内容声明为 extern
?
这个问题背后的原因与上面相同:我不希望在包含 .h
文件时出现意外。
另外,如果我是对的,这是一个常见的错误吗?我的意思是在现实世界的编程和“真实”的项目中。
谢谢。
In 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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
您绝对不应该在标头中使用
using namespace
,正如您所说的那样,它可能会意外地更改包含该标头的任何其他文件中的代码含义。无法撤消using namespace
这是它如此危险的另一个原因。我通常只使用 grep 或类似的东西来确保using namespace
不会在标头中被调用,而不是尝试任何更复杂的事情。静态代码检查器可能也会标记这一点。标头应仅包含需要编译的标头。强制执行此操作的一个简单方法是始终将每个源文件自己的标头作为第一件事包含在任何其他标头之前。如果标头不是独立的,则源文件将无法编译。在某些情况下,例如引用库中的实现细节类,您可以使用前向声明而不是#include,因为您可以完全控制此类前向声明类的定义。
我不确定我是否会称其为常见,但它肯定偶尔会出现一次,通常是由不知道负面后果的新程序员编写的。通常,只需进行一些有关风险的教育就可以解决所有问题,因为解决起来相对简单。
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 ausing namespace
which is another reason it's so dangerous. I typically just usegrep
or the like to make sure thatusing 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.
Sutter 和 Alexandrescu 的 “C++ 编码标准:101 条规则、指南和最佳实践”中的第 59 条:
头文件是一个或多个源文件中的一个客体。包含
using
指令和声明的头文件也带来了它的吵闹伙伴。using
声明引入了一个伙伴。using
指令引入命名空间中的所有伙伴。您的教师对using namespace std;
的使用是一个 using 指令。更严重的是,我们有命名空间来避免名称冲突。头文件旨在提供一个接口。大多数标头不知道现在或将来哪些代码可能包含它们。为了内部方便,在标头中添加 using 语句会将这些方便的名称强加给该标头的所有潜在客户端。这可能会导致名称冲突。这简直是粗鲁无礼。
Item 59 in Sutter and Alexandrescu's "C++ Coding Standards: 101 Rules, Guidelines, and Best Practices":
A header file is a guest in one or more source files. A header file that includes
using
directives and declarations brings its rowdy buddies over too.A
using
declaration brings in one buddy. Ausing
directive brings in all the buddies in the namespace. Your teachers' use ofusing namespace std;
is a using directive.More seriously, we have namespaces to avoid name clash. A header file is intended to provide an interface. Most headers are agnostic of what code may include them, now or in the future. Adding
using
statements for internal convenience within the header foists those convenient names on all the potential clients of that header. That can lead to name clash. And it's just plain rude.在标题中包含标题时需要小心。在大型项目中,它可能会创建一个非常混乱的依赖链,从而触发比实际需要更大/更长的重建。查看这篇文章和其后续内容,详细了解良好物理结构在 C++ 项目中的重要性。
仅当绝对需要时(每当需要类的完整定义时)才应在标头内包含标头,并尽可能使用前向声明(当需要的类是指针或引用时)。
至于命名空间,我倾向于在头文件中使用显式命名空间范围,并且只在我的 cpp 文件中放置
using namespace
。You need to be careful when including headers inside of headers. In large projects, it can create a very tangled dependency chain that triggers larger/longer rebuilds than were actually necessary. Check out this article and its follow-up to learn more about the importance of good physical structure in C++ projects.
You should only include headers inside a header when absolutely needed (whenever the full definition of a class is needed), and use forward declaration wherever you can (when the class is required is a pointer or a reference).
As for namespaces, I tend to use the explicit namespace scoping in my header files, and only put a
using namespace
in my cpp files.关于“是否有某种方法可以撤消 [a
using
声明]?”我认为指出
using
声明受范围影响是有用的。所以有效的是。通过限制
using
声明的范围,其效果仅在该范围内持续;当该范围结束时,它会被“撤消”。当
using
声明在任何其他作用域之外的文件中声明时,它具有文件作用域并影响该文件中的所有内容。对于头文件,如果
using
声明位于文件范围内,则这将扩展到包含该头文件的任何文件的范围。With regards to "Is there some way to undo [a
using
declaration]?"I think it is useful to point out that
using
declarations are affected by scope.So effectively yes. By limiting the scope of the
using
declaration its effect only lasts within that scope; it is 'undone' when that scope ends.When the
using
declaration is declared in a file outside of any other scope it has file-scope and affects everything in that file.In the case of a header file, if the
using
declaration is at file-scope this will extend to the scope of any file the header is included in.查看戈达德太空飞行中心编码标准(针对 C 和 C++)。事实证明,这比以前要困难一些 - 请参阅 SO 问题的更新答案:
GSFC C++ 编码标准说:
第一个交叉引用问题现在包括 GSFC C 编码标准的引用及其基本原理,但实质内容最终是相同的。
Check out the Goddard Space Flight Center coding standards (for C and C++). That turns out to be a bit harder than it used to be - see the updated answers to the SO questions:
The GSFC C++ coding standard says:
The first of the cross-referenced questions now includes a quote from the GSFC C coding standard, and the rationale, but the substance ends up being the same.
您是对的,在标头中使用名称空间是危险的。
我不知道如何撤消它。
检测它很容易,但只需在头文件中搜索
using namespace
即可。由于最后一个原因,它在实际项目中并不常见。如果有人做了类似的事情,更有经验的同事很快就会抱怨。
在实际项目中,人们试图最大限度地减少包含文件的数量,因为包含的文件越少,编译速度就越快。这节省了每个人的时间。但是,如果头文件假定应在其之前包含某些内容,则它本身应包含该内容。否则它会使标头不独立。
You are right that
using namespace
in header is dangerous.I do not know a way how to undo it.
It is easy to detect it however just search for
using namespace
in header files.For that last reason it is uncommon in real projects. More experienced coworkers will soon complain if someone does something like it.
In real projects people try to minimize the amount of included files, because the less you include the quicker it compiles. That saves time of everybody. However if the header file assumes that something should be included before it then it should include it itself. Otherwise it makes headers not self-contained.
我相信,如果您在如下所示的嵌套命名空间中编写声明,则可以安全地在 C++ 标头中使用“using”:
这应该仅包含在“DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED”中声明的内容,而不包含使用的命名空间。我已经在 mingw64 编译器上测试过了。
I believe you can use 'using' in C++ headers safely if you write your declarations in a nested namespace like this:
This should include only the things declared in 'DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED' without the namespaces used. I have tested it on mingw64 compiler.
你是对的。并且任何文件都应该只包含该文件所需的标头。至于“在现实世界的项目中做错事很常见吗?” - 哦是的!
You are right. And any file should only include the headers needed by that file. As for "is doing things wrong common in real world projects?" - oh, yes!
就像编程中的所有事情一样,实用主义应该战胜教条主义,IMO。
只要您在项目范围内做出决定(“我们的项目广泛使用 STL,并且我们不想在所有内容前添加 std::。”),我就看不出它有什么问题。毕竟,您面临的唯一风险是名称冲突,而且随着 STL 的普遍存在,这不太可能成为问题。
另一方面,如果这是一个开发人员在单个(非私有)头文件中做出的决定,我可以看到它会如何在团队中产生混乱,应该避免。
Like all things in programming, pragmatism should win over dogmatism, IMO.
So long as you make the decision project-wide ("Our project uses STL extensively, and we don't want to have to prepend everything with std::."), I don't see the problem with it. The only thing you're risking is name collisions, after all, and with the ubiquity of STL it's unlikely to be a problem.
On the other hand, if it was a decision by one developer in a single (non-private) header-file, I can see how it would generate confusion among the team and should be avoided.