C++ 标头中的“using namespace” [duplicate]

"using namespace" in c++ headers [duplicate]

提问人:Baruch 提问时间:5/1/2011 更新时间:12/11/2019 访问量:113592

问:

在我们所有的 c++ 课程中,所有老师总是在他们的文件中将 s 放在后面。在我看来,这似乎是危险的,因为从那时起,通过将该标头包含在另一个程序中,我将把命名空间导入到我的程序中,也许没有意识到、打算或想要它(标头包含可以嵌套得非常深)。using namespace std;#include.h

所以我的问题是双重的:我是否正确,不应该在头文件中使用,和/或是否有某种方法可以撤消它,例如:using namespace

//header.h
using namespace std {
.
.
.
}

还有一个类似的问题:头文件应该归档它对应文件需要的所有头文件,只归档头定义所需的头文件,让文件处理其余部分,或者什么都不归档,并声明它需要的所有内容?
这个问题背后的原因与上面相同:我不希望在包含文件时出现意外。
#include.cpp.cpp#includeextern.h

另外,如果我是对的,这是一个常见的错误吗?我的意思是在现实世界的编程和“真实”项目中。

谢谢。

C++ 命名空间 头文件

评论

3赞 Richard Inglis 5/1/2011
stackoverflow.com/questions/1265039/using-std-namespace
3赞 Marius Bancila 5/2/2011
顺便说一句,如果由于语句而出现名称冲突,则可以使用完全限定名称来解决问题。using namespace

答:

4赞 user2100815 5/1/2011 #1

你是对的。任何文件都应仅包含该文件所需的标头。至于“在现实世界的项目中做错事很常见吗?”——哦,是的!

5赞 Öö Tiib 5/1/2011 #2

你是对的,在标题中是危险的。 我不知道如何撤消它。 它很容易检测到,但只需在头文件中搜索即可。 由于最后一个原因,这在实际项目中并不常见。如果有人做类似的事情,更有经验的同事很快就会抱怨。using namespaceusing namespace

在实际项目中,人们会尽量减少包含的文件数量,因为包含的文件越少,编译速度就越快。这样可以节省每个人的时间。但是,如果头文件假定应该在它之前包含某些内容,那么它应该包含它本身。否则,它会使标头不是独立的。

13赞 Mike O'Connor 5/2/2011 #3

在标头内包含标头时需要小心。在大型项目中,它可能会创建一个非常纠结的依赖链,触发比实际需要的更大/更长的重建。查看本文及其后续内容,详细了解良好物理结构在 C++ 项目中的重要性。

只有在绝对需要时(每当需要类的完整定义时),才应在标头中包含标头,并尽可能使用正向声明(当需要类时是指针或引用)。

至于命名空间,我倾向于在我的头文件中使用显式命名空间范围,并且只在我的 cpp 文件中放置一个。using namespace

评论

3赞 Chris 3/11/2018
如何简化函数声明?这必须发生在标题中,不是吗?template
140赞 Mark B 5/2/2011 #4

您绝对不应该在标头中使用,因为您所说的正是因为它可以意外地更改包含该标头的任何其他文件中代码的含义。没有办法撤消,这是它如此危险的另一个原因。我通常只是使用或类似的东西来确保它不会在标头中被调用,而不是尝试任何更复杂的东西。可能静态代码检查器也会标记这一点。using namespaceusing namespacegrepusing namespace

标头应仅包含需要编译的标头。强制执行此操作的一种简单方法是始终将每个源文件自己的标头作为第一件事,而不是任何其他标头。然后,如果标头不是独立的,则源文件将无法编译。在某些情况下,例如,引用库中的实现详细信息类,可以使用正向声明,而不是因为您可以完全控制此类正向声明类的定义。#include

我不确定我是否会称它为常见,但它肯定会偶尔出现,通常是由没有意识到负面后果的新程序员编写的。通常,只需对风险进行一些教育即可解决任何问题,因为它相对容易解决。

评论

3赞 Chris 3/11/2018
我们可以自由地在我们的文件中使用语句吗?S是指尖的死亡。using.cpp3rdPartyLib::BigClassName<3rdPartyLib::AnotherBigName,3rdPartyLib::AnotherBigName>::Iterator
2赞 Chris 3/11/2018
我们应该如何简化应该在标题中的函数? ?templatetypedefs
1赞 tjwrona1992 5/31/2019
@donlan,你似乎很长一段时间都没有得到回应......是的,您可以在文件中使用语句而不用太担心,因为范围将仅限于该文件,但永远不要在语句之前这样做。至于标头中定义的模板函数,不幸的是,除了写出命名空间之外,我不知道一个好的解决方案......也许你可以把一个声明放在一个单独的范围内,这至少可以防止它转义当前文件。using.cpp#includeusing{ /* using statement in between brackets */ }
4赞 ijprest 5/2/2011 #5

就像编程中的所有事情一样,实用主义应该战胜教条主义,IMO。

只要你在项目范围内做出决定(“我们的项目广泛使用 STL,我们不想用 std::.”来预置所有内容“),我就看不出它有什么问题。毕竟,你唯一要冒的风险就是名称冲突,而且随着STL的无处不在,这不太可能成为问题。

另一方面,如果这是一个开发人员在单个(非私有)头文件中的决定,我可以看到它会在团队中产生混乱,应该避免。

37赞 Andy Thomas 5/2/2011 #6

Sutter 和 Alexandrescu 的“C++ 编码标准:101 条规则、指南和最佳实践”中的第 59 项:

59. 不要在头文件中或 #include 之前编写命名空间 usings。

命名空间是为了方便你,而不是为了你强加给别人:永远不要在指令之前写声明或指令。usingusingusing#include

推论:在头文件中,不要编写命名空间级别的指令或声明;相反,显式命名空间限定所有名称。usingusing

头文件是一个或多个源文件中的来宾。包含指令和声明的头文件也会吸引吵闹的伙伴。using

一份宣言带来了一个伙伴。指令引入命名空间中的所有好友。教师的 use of 是 using 指令。usingusingusing namespace std;

更严重的是,我们有命名空间来避免名称冲突。头文件旨在提供接口。大多数标头都不知道现在或将来可能包含哪些代码。为了内部方便,在标头中添加语句会将这些方便的名称强加给该标头的所有潜在客户。这可能会导致名称冲突。这简直是粗鲁的。using

7赞 Jonathan Leffler 5/2/2011 #7

查看戈达德太空飞行中心编码标准(适用于 C 和 C++)。事实证明,这比以前要难一些 - 请参阅 SO 问题的更新答案:

GSFC C++编码标准说:

§3.3.7 每个头文件都应包含它需要编译的文件,而不是强迫用户使用所需的文件。 应限于标头需要的内容;其他应放在源文件中。#include#include#includes#includes

第一个交叉引用的问题现在包括对 GSFC C 编码标准的引用和基本原理,但实质最终是相同的。

4赞 AnArrayOfFunctions 11/17/2014 #8

我相信如果你在嵌套命名空间中编写声明,你可以安全地在 C++ 标头中使用“使用”,如下所示:

namespace DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED
{
    /*using statements*/

    namespace DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED
    {
        /*declarations*/
    }
}

using namespace DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED::DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED;

这应该只包括在“DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED”中声明的内容,而不使用命名空间。我已经在 mingw64 编译器上对其进行了测试。

评论

2赞 Anthony Hall 12/17/2016
这是我以前从未见过的有用技术;谢谢。通常,我可以使用全范围限定,并尽可能将声明放在函数定义中,这样它们就不会污染函数之外的命名空间。但是现在我想在头文件中使用 C++11 个用户定义的文字,并且按照通常的约定,文字运算符受命名空间保护;但我不想在构造函数初始值设定项列表中使用它们,这些列表不在我可以使用非污染声明的范围内。所以这对于解决这个问题很有帮助。usingusing
0赞 Anthony Hall 12/17/2016
尽管此模式的一个不幸的副作用是,在最内层命名空间中声明的任何类都将显示在编译器错误消息中,并带有完全限定的名称:。至少,这就是我在 g++ 中发生的事情。error: ... DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED:: DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED::ClassName ...
11赞 YoungJohn 2/27/2016 #9

关于“有没有办法撤消[声明]?using

我认为有必要指出,声明受范围的影响。using

#include <vector>

{   // begin a new scope with {
    using namespace std;
    vector myVector;  // std::vector is used
}   // end the scope with }

vector myOtherVector;   // error vector undefined
std::vector mySTDVector // no error std::vector is fully qualified

所以有效是的。通过限制声明的范围,其效力只在该范围内持续;当该范围结束时,它将被“撤消”。using

当声明在任何其他范围之外的文件中声明时,它具有文件范围并影响该文件中的所有内容。using

对于头文件,如果声明在文件范围内,这将扩展到包含头的任何文件的范围。using

评论

5赞 rustypaper 1/9/2017
你似乎是唯一一个如何理解实际问题的人......但是,我的编译对我使用类内减速不太满意。
0赞 TafT 11/20/2018
通过解释 OP 关于范围应该如何工作(如声明内容)与它实际如何工作(如变量)的想法的问题,这个答案可以做得更好。 在它不做任何与之相关的操作之后,它限制了它的范围。这是一种偶然的方式,可以在全球范围内应用。namespace{}{}using namespace