为什么“使用命名空间标准”被认为是不好的做法?

Why is "using namespace std;" considered bad practice?

提问人:akbiggs 提问时间:9/21/2009 最后编辑:Mateen Ulhaqakbiggs 更新时间:7/13/2023 访问量:1196107

问:

我听说这是不好的做法,我应该直接使用。 为什么会这样?声明与命名空间中的内容同名的变量是否有风险?using namespace std;std::coutstd::cinstd

C 命名空间 std using-directives c++-faq

评论

723赞 Bill 9/21/2009
别忘了你可以做:“使用 std::cout;”,这意味着你不必键入 std::cout,但不要同时引入整个 std 命名空间。
122赞 sh- 6/25/2017
在头文件中的文件范围内使用“using namespace std”尤其糟糕。毕竟在文件范围的源文件 (*.cpp) 中使用它并没有那么糟糕,因为它的效果仅限于单个翻译单元。在函数或类中使用它的问题就更小了,因为它的效果仅限于函数或类范围。
15赞 Ludovic Zenohate Lagouardette 7/19/2017
我不鼓励使用 using 指令,但对于特定的命名空间,如 , , 以及将处理文字或可读性技巧的东西。每当它位于头文件或实现文件中时。我猜在函数范围内可能没问题,但除了文字和东西之外,它没有用。std::literals::chrono_literalsPoco::Data:KeywordsPoco::Units
23赞 sh- 4/9/2018
@Jon:这与命名空间 std 无关。我的重点在于“在头文件中的文件范围内”。作为一个建议:不要在头文件的文件范围内使用“using namespace”(std 或其他)。可以在实现文件中使用它。对不起,含糊不清。
16赞 Danra 8/11/2019
这在标头中只被认为是不好的做法。在其他地方未包含的源文件(即 .cpp 文件)中也可以。请参阅下面的@mattnewport的答案。stackoverflow.com/a/26722134/125997

答:

65赞 Martin Beckett 9/21/2009 #1

另一个原因是惊喜。

如果我看到,而不是我想:这是什么?这是正常的吗?有什么特别的吗?cout << blahstd::cout << blahcoutcout

评论

43赞 Brent Rittenhouse 3/6/2018
这是在开玩笑吗?我真的说不出来。如果不是,那么我个人会认为这是正常的“cout”,除非你不信任代码,否则这将是 BEYOND MAJOR 代码的味道,IMO。...如果你不信任代码,那么你为什么要首先使用它呢?请注意,我不是在说“TRUST EvERYThING!”,但如果你正在处理 GitHub 或其他一些知名库或其他东西,这似乎也有点牵强。
55赞 James Hollis 4/6/2018
@BrentRittenhouse是一个坏例子,因为每个人都认识到这一点。但想象一下,在一个金融应用程序中。是在指定日期买卖某物的合同吗?不,不是。如果代码说,你就不会那么容易混淆了。coutfuturestd::future
2赞 Swift - Friday Pie 4/25/2018
@BrentRittenhouse可能是一个有点不好的例子,至少有四个不同的库具有 cout。可能是“是标准库吗?libstdc++?STL?还有别的吗?不,不是每个人都知道 std::cout,至少从本质上讲,我们收到的 7 个新工人中有 6 个不知道。因为教育课程不使用教育中的那些。我必须赶走printfs。或者debugs() - 来自Qt。
3赞 mckenzm 7/29/2019
真?它几乎是许多关于 C++ 的书籍第一章的第一个示例,如果有的话,它(使用插入运算符)是一些新人唯一知道的 C++。
0赞 Martin Beckett 7/31/2019
@mckenzm我可能会把它放在书本或讲义中以减少混乱,但不会放在代码中
2833赞 Greg Hewgill 9/21/2009 #2

考虑两个名为 Foo 和 Bar 的库:

using namespace foo;
using namespace bar;

一切正常,您可以从 Foo 和 Bar 毫无问题地拨打电话。但是有一天,您升级到 Foo 2.0 的新版本,它现在提供了一个名为 .现在你遇到了一个冲突:Foo 2.0 和 Bar 都导入到你的全局命名空间中。这将需要一些努力来修复,特别是如果函数参数恰好匹配。Blah()Quux()Quux()Quux()

如果您使用了 和 ,那么引入 将不是一个事件。foo::Blah()bar::Quux()foo::Quux()

评论

587赞 paxdiablo 9/21/2009
我一直很喜欢 Python 的“import big_honkin_name as bhn”,所以你可以只使用“bhn.something”而不是“big_honkin_name.something”——真的减少了打字。C++ 有类似的东西吗?
931赞 Khaled Alshaya 9/21/2009
@Pax命名空间 io = boost::filesystem;
181赞 MattyT 9/21/2009
我认为说这是“一些努力来修复”是夸大其词的事情。您将没有新 foo::Quux 的实例,因此只需使用 bar::Quux 消除当前所有用法的歧义即可。
349赞 erikkallen 9/22/2009
任何明智的人都会创建一个具有非限定名称与 std 类型冲突的类型的库吗?
131赞 sbi 9/22/2009
@erikkallen:std 库已经采用了数百个(甚至数千个)名称,其中许多非常流行和常见(,,),IIRC 是将其放入自己的命名空间的重要原因。errorlistsort
28赞 Preet Sangha 9/21/2009 #3

这一切都与管理复杂性有关。使用命名空间会拉入你不想要的东西,因此可能会使调试变得更加困难(我说可能)。在任何地方使用 std:: 更难阅读(更多文本等等)。

课程的马匹 - 以最佳方式管理您的复杂性,并感觉自己有能力。

评论

0赞 metamorphosis 2/23/2021
“使用命名空间会拉出你不想要的东西,因此可能会使调试变得更加困难(我说可能)。使用命名空间不会“拉入”任何内容。调试不受影响。
0赞 Preet Sangha 2/24/2021
这取决于你如何定义拉动东西。在上面的上下文中,使用它意味着 std:: 命名空间中的所有内容都被视为与作用域有关。任何标识符都可能来自该命名空间,因此在读取代码时必须考虑这一点。它会产生一种歧义,如果您仅在需要时引用具有命名空间的内容,则根本不存在这种歧义。任何能减少读者认知负荷的东西(例如,代码生命周期的绝大多数时间)都是一件好事,相反,任何增加认知负荷的东西都是坏事。因此,我在最后声明。
0赞 metamorphosis 2/27/2021
在这种情况下使用“pull things in”会给人一种错误的印象 - 它给人的印象是,无论你的意思如何,程序中都会包含额外的命名空间声明。我同意你所说的关于认知负荷的观点。
6赞 MathGladiator 9/21/2009 #4

这取决于它的位置。如果它是一个公共标头,则通过将命名空间合并到全局命名空间中来减少命名空间的值。请记住,这可能是制作模块全局变量的一种巧妙方法。

24赞 Ron Warholic 9/21/2009 #5

考虑

// myHeader.h
#include <sstream>
using namespace std;


// someoneElses.cpp/h
#include "myHeader.h"

class stringstream {  // Uh oh
};

请注意,这是一个简单的示例。如果您有包含 20 个包含和其他导入的文件,您将需要通过大量依赖项来找出问题所在。更糟糕的是,您可能会在其他模块中获得不相关的错误,具体取决于冲突的定义。

这并不可怕,但通过不在头文件或全局命名空间中使用它,您可以避免头痛。在非常有限的范围内执行此操作可能是可以的,但是我从未遇到过键入额外的五个字符以阐明我的函数来自哪里的问题。

评论

0赞 mercury0114 11/8/2020
当然,如果只存在于实现文件中呢?using namespace std
575赞 ChrisW 9/21/2009 #6

放入类的头文件的问题在于,它迫使任何想要使用您的类(通过包含您的头文件)的人也“使用”(即查看其他命名空间中的所有内容)。using namespace

但是,您可以随意将 using 语句放在您的(私有)*.cpp 文件中。


请注意,有些人不同意我这样说的“随意”——因为尽管 cpp 文件中的语句比头文件中的语句更好(因为它不会影响包含头文件的人),但他们认为它仍然不好(因为根据代码的不同,它可能会使类的实现更难维护)。这个 C++ 超级常见问题解答条目说,using

using-directive 存在于旧版 C++ 代码中,以简化向命名空间的转换,但您可能不应该定期使用它,至少不应该在新的 C++ 代码中使用它。

常见问题解答建议了两种替代方案:

  • 使用声明:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
    
  • 只需输入 std::

    std::cout << "Values:";
    

评论

9赞 Móż 11/2/2019
当然,你也不应该假设全局 cout 的状态,以免有人在 std:cout << std::hex 之后未能执行 std::restore_cout_state。但那是另一回事。
0赞 Secundi 12/16/2020
“但是,您可以随意在(私有)*.cpp文件中放置一个 using 语句。”如果未来的开发团队决定更改翻译单元方案,例如通过 UnityBuilds,该怎么办?如有疑问,您最终会得到可怕的未定义行为。
0赞 Dimitrios Menounos 12/21/2020
虽然对头文件的担忧是有道理的,但由于包含的方式可能会产生副作用,我觉得它们不适用于 cpp 文件。让我们看看几乎所有其他编程语言中会发生什么。例如,当你用 Java 编写代码时,你几乎总是从你使用的包中导入每个符号——尤其是标准符号。这意味着您几乎从不期望 String、List、Map 等的竞争和冲突实现。我所知道的其他语言也是如此。这是合理的IMO,我们应该让生活变得轻松而不是困难。
0赞 Kiruahxh 3/11/2021
如果一个团队迁移到 unity build,它将不得不删除 using 关键字并哭泣,因为使用 stdlib 而不使用 st 是一种痛苦。但是,如果您依赖 Qt,这没关系,因为 Qt 不使用命名空间(祝福它们)。尽管如此,Unity 构建仍然是一个边缘案例。
2赞 spectras 4/9/2021
...给你。另一方面,对于绝大多数 C++ 生态系统,包括 C++ 委员会、经验丰富的 C++ 开发人员和 C++ 语言的创建者本人的共同智慧,这不仅是一种选择,而且也是推荐的选择。
88赞 sth 9/21/2009 #7

如果导入正确的头文件,则全局范围中突然出现十六进制、加号计数等名称。如果您不知道包含这些名称,这可能会令人惊讶。如果您还尝试在本地使用这些名称,可能会导致相当多的混淆。std::

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

评论

15赞 Cheers and hth. - Alf 12/15/2012
+1 更不用说了.尽管如此,我还是更喜欢非限定名称,因为这增加了我的可读性。另外,我认为我们通常不会在口头演讲中限定事物,并且愿意花时间解决可能的歧义,这意味着能够在没有限定的情况下理解一个人在谈论什么是有价值的,并应用于源代码,这意味着它的结构方式即使没有限定也很清楚它的全部内容。distance
0赞 einpoklum 2/25/2016
不过,公平地说,如果你不包括 .不过,好点子。<iomanip>
1赞 Aykhan Hagverdili 7/29/2020
@einpoklum 您通常不必包括这些内容即可获得这些内容。包括对海湾合作委员会的所有人来说都足够了,因为 gcc.godbolt.org/z/Kqx9q1<iomanip><iostream>
0赞 celticminstrel 8/7/2021
可以肯定的是,您只需要接受参数的操纵器,例如 .<iomanip>setw
0赞 user2793784 8/26/2022
我个人的看法:任何与 STD 的名称冲突都是一个错误,一旦发现就应该立即修复
7赞 Dr. Watson 9/21/2009 #8

我不认为这在所有条件下都一定是不好的做法,但使用时需要小心。如果你正在编写一个库,你可能应该将作用域解析运算符与命名空间一起使用,以防止你的库与其他库发生冲突。对于应用程序级代码,我看不出它有什么问题。

20赞 Dustin Getz 9/21/2009 #9
  1. 你需要能够阅读那些与你有不同风格和最佳实践意见的人编写的代码。

  2. 如果您只使用 ,没有人会感到困惑。但是,当你有很多命名空间飞来飞去,你看到这个类,但你并不完全确定它的作用时,让命名空间显式充当某种注释。乍一看,你可以看到,“哦,这是一个文件系统操作”或“正在做网络工作”。cout

1710赞 sbi 9/21/2009 #10

它可能比格雷格写的更糟糕

库 Foo 2.0 可以引入一个函数,该函数与多年来调用的代码相比,它显然更适合您的某些调用。然后你的代码仍然可以编译但它会静默地调用错误的函数,并且天知道会发生什么。这和事情可能变得一样糟糕。Quux()Quux()bar::Quux()

请记住,命名空间有大量的标识符,其中许多是非常常见的标识符(例如、、、等),它们也很可能出现在其他代码中。stdlistsortstringiterator

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


这里还有一个数据点:很多很多年前,我也曾经发现必须用 .然后我参与了一个项目,在一开始就决定禁止指令和声明,除了函数范围。你猜怎么着?我们大多数人花了几周的时间来习惯编写前缀,几周后,我们大多数人甚至同意它实际上使代码更具可读性。这是有原因的:你喜欢短篇还是长篇散文是主观的,但前缀客观地增加了代码的清晰度。不仅是编译器,您也更容易看到所引用的标识符。std::using

在十年内,这个项目发展到有几百万行代码。由于这些讨论一次又一次地出现,我曾经很好奇(允许的)函数范围在项目中实际使用的频率是多少。我搜索了它的来源,只找到了一二十个使用它的地方。在我看来,这表明,一旦尝试过,开发人员也不会发现使用使用指令的痛苦程度,即使每 100 kLoC 使用一次,即使允许使用。usingstd::


一句话:在所有内容前面明确添加前缀不会造成任何伤害,几乎不需要习惯,并且具有客观优势。特别是,它使代码更容易被编译器和人类读者解释——这可能是编写代码时的主要目标。

评论

1赞 convert 2/10/2022
不同意读者的解释,因为 foo::bar() 可以表示来自命名空间 foo 的函数栏或来自类 foo 的静态函数。
6赞 Stefan Riedel 2/14/2022
@convert 为什么有人会打电话给一个班级而不是?并且静态方法也应该被调用而不是.这就是为什么人们认为公约是一件好事。fooFooFoo::BarFoo::bar
1赞 convert 2/14/2022
@Stefan Riedel:不知道,但这是C++的comon练习。例如,它是字符串和向量,而不是字符串和向量。
5赞 Stefan Riedel 2/14/2022
@convert这是标准库中的常见做法。大多数(据我所知)C++ 编码约定都推荐大写类。据我所知,超过一半的约定推荐大写的静态方法。即使你有一些巫毒教的编码约定,两者都不行,作为静态方法仍然没有反对解释点的论据。该函数/方法属于哪个位置仍然更清楚,如果你给你的类起一个好名字,它仍然很清楚一个类是指类而不是命名空间。foo::bar
12赞 Sz. 2/16/2022
@convert:“别再玩死灵法师了” 这不是一个聊天框,也不是组织节日的论坛,日历时间本身就是一个因素。这是一个知识库,其中日期本身是无关紧要的,相关性一致性等因素很重要。这个主题(问题)既有答案,也有答案。因此,“我们应该停止”对 SO 的误解。(注意:您实际上在这里得到了奖励,可以以有用的方式更新旧项目。
36赞 Yelonek 9/21/2009 #11

我也认为这是一种不好的做法。为什么?就在有一天,我以为命名空间的功能是划分东西,所以我不应该把所有东西都扔进一个全局包里来破坏它。

但是,如果我经常使用“cout”和“cin”,我会在 .cpp 文件中写:(从不在头文件中,因为它传播 )。我认为没有一个理智的人会命名一个流或.;)using std::cout; using std::cin;#includecoutcin

评论

8赞 sbi 5/26/2012
这是一个本地 using 声明,与 using 指令截然不同。
144赞 robson3.14 9/21/2009 #12

不应在全局范围内使用该指令,尤其是在标头中。但是,在某些情况下,即使在头文件中也是如此: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));
}

这比显式限定 (, ...) 更好,因为它更短,并且能够使用用户定义的浮点类型(通过依赖于参数的查找 (ADL))。std::sinstd::cos

评论

4赞 Zan Lynx 6/25/2011
@Billy:没有其他方法可以支持调用 userlib::cos(userlib::superint)。每个功能都有其用途。
20赞 Billy ONeal 6/25/2011
@Zan:当然有。 等。但问题是,任何设计良好的方法都会有自己的命名空间,所以这真的对你没有帮助。(除非之前有一个模板,而且和 -- 一样糟糕,而且范围没有限制。此外,我见过的唯一这样的功能是 ,在这种情况下,我建议只创建一个模板专用化并避免整个问题。using std::cos;using std::sinuserlibsincosusing namespace userlibusing namespace stdswapstd::swap
13赞 sbi 5/30/2012
@BillyONeal:(没有函数模板部分专用化 (FTPS),因此有时需要改用重载。template<typename T> void swap(MyContainer<T>&, MyContainer<T>&)
43赞 j_random_hacker 9/4/2015
@BillyONeal:你的评论(7次被点赞!)是错误的 - 你描述的情况正是ADL所要涵盖的。简而言之,如果有一个或多个“关联的命名空间”(例如,如果它在 中定义),那么任何看起来像的函数调用都会额外查看这些命名空间 - 不需要任何事先。Zan Lynx是对的(C++名称查找是拜占庭式的...xnamespace userlibcos(x)using namespace userlib;
5赞 Ferruccio 5/11/2016
而不是 ,我更喜欢 .您可以获得相同的好处,而不会产生任何转储到函数中的风险。using namespace std;using std::sin; using std::cos; using std::exp;std::*
273赞 David Thornley 10/29/2010 #13

我最近遇到了一个关于Visual Studio 2010的投诉。事实证明,几乎所有的源文件都有这两行:

using namespace std;
using namespace boost;

许多 Boost 功能都进入了 C++0x 标准,而 Visual Studio 2010 有很多 C++0x 功能,所以突然之间这些程序没有编译了。

因此,避免是一种面向未来的形式,一种确保对正在使用的库和/或头文件的更改不会破坏程序的方法。using namespace X;

评论

31赞 einpoklum 2/25/2016
这。Boost 和 std 有很多重叠 - 尤其是自 C++11 以来。
2赞 Ferruccio 4/10/2018
我曾经这样做过一次,并以艰难的方式吸取了教训。现在,我从不在函数定义之外使用,也很少使用。usingusing namespace
0赞 convert 2/10/2022
我个人永远不会使用boost,因为它是我见过的最糟糕的C++ API。如果使用命名空间 std,我仍然会遇到哪些问题?
0赞 wheredidthatnamecomefrom 3/17/2022
@convert 从理论上讲,任何库现在或将来都可能与 std 发生冲突。正如其他答案中提到的,std 包含许多常见名称,如 list 和 error。Boost 只是突出了现在受到影响的问题。调用 using 撤消应该修复的命名空间。小心它。
52赞 Alexander Poluektov 3/29/2011 #14

有经验的程序员使用任何能解决他们问题的东西,避免任何产生新问题的东西,并且出于这个确切的原因,他们避免使用头文件级别的 using-directives。

有经验的程序员也会尽量避免在源文件中对名称进行完全限定。造成这种情况的一个小原因是,除非有充分的理由,否则当更少的代码就足够时,编写更多的代码是不优雅的。造成这种情况的一个主要原因是关闭了依赖于参数的查找 (ADL)。

这些很好的理由是什么?有时程序员明确想要关闭 ADL,有时他们希望消除歧义。

所以以下几点是可以的:

  1. 函数实现中的函数级 using-directives 和 using-declarations
  2. 源文件内的源文件级 using-declarations
  3. (有时)源文件级 using-directives
114赞 towi 1/18/2013 #15

不要全局使用它

只有在全球范围内使用时,它才被认为是“坏的”。因为:

  • 你把你正在编程的命名空间弄得乱七八糟。
  • 当您使用多个 .using namespace xyz;
  • 对于源代码的其他读者来说,无论对什么是正确的,对于最频繁的读者来说都更是如此:你自己。一两年后再来看看......
  • 如果你只谈论,你可能不知道你抓取的所有东西 - 当你添加另一个或移动到一个新的 C++ 修订版时,你可能会得到你不知道的名称冲突。using namespace std;#include

您可以在本地使用它

继续在本地(几乎)自由使用它。当然,这阻止了你重复 -- 重复也是不好的。std::

在本地使用它的成语

C++03 中,有一个习惯用语 - 样板代码 - 用于实现类的函数。有人建议你实际使用本地 -- 或者至少:swapusing 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(...)`
}

这有以下魔力:

  • 编译器将选择 for ,即 .std::swapvalue_void std::swap(int, int)
  • 如果实现了重载,编译器将选择它。void swap(Child&, Child&)
  • 如果你没有这个重载,编译器将使用并尽力交换它们。void std::swap(Child&,Child&)

C++11 中,没有理由再使用此模式。更改了实现,以查找潜在的重载并选择它。std::swap

评论

7赞 Christian Rau 3/8/2013
“std::swap 的实现已更改,以查找潜在的过载并选择它。”-什么?你确定吗?尽管在 C++11 中,首先提供自定义确实不再那么重要,因为它本身更灵活(使用移动语义)。但是自动选择你自己的自定义交换,这对我来说绝对是新的(我真的不相信)。swapstd::swapstd::swap
0赞 towi 3/8/2013
@ChristianRau 我想是的,是的。我在某处的 SO 上读到过这篇文章。我们总是可以问霍华德,他应该知道。我现在正在挖掘和挖掘......
19赞 Adrian McCarthy 2/28/2014
即使在交换的情况下,更清晰(谢天谢地更常见)的成语是 write 而不是 .更具体的习语具有较少的副作用,因此使代码更易于维护。using std::swap;using namespace std;
16赞 Jonathan Wakely 7/16/2015
最后一句话是错误的。在 C++11 中,标准交换两步被正式祝福为正确的调用方式,标准中的其他地方也被更改为这样调用(注意如上所述,是正确的方式,而不是)。但本身并没有被改变以找到其他一些东西并使用它。如果被调用,则被使用。swapswapusing std::swapusing namespace stdstd::swapswapstd::swapstd::swap
6赞 Lundin 10/26/2015
不过,更明智的做法是只在本地键入,以减少本地命名空间,同时创建自记录代码。你很少对整个 std 命名空间感兴趣,所以只要挑选出你感兴趣的部分就行了。using std::swap
4赞 harris 4/9/2013 #16

是的,命名空间很重要。进入我的项目后,我需要将一个 var 声明导入到我的源代码中,但在编译它时,它与另一个第三方库冲突。

最后,我不得不通过其他方式解决它,并使代码不那么清晰。

7赞 August Karlstrom 4/11/2013 #17

对于不合格的导入标识符,您需要像 grep 这样的外部搜索工具来找出标识符的声明位置。这使得对程序正确性的推理变得更加困难。

7赞 Solkar 5/13/2013 #18

“为什么'使用命名空间标准'在C++中被认为是一种不好的做法?”

我反过来说:为什么输入五个额外的字符被一些人认为很麻烦?

例如,考虑编写一个数值软件。当“vector”是问题域最重要的概念之一时,为什么我甚至会考虑通过将一般的“std::vector”削减为“vector”来污染我的全局命名空间?

评论

23赞 Jeremy Friesner 9/3/2013
这不仅仅是 5 个额外的字符;每次引用标准库中的任何对象类型时,它都会有 5 个额外的字符。如果您经常使用标准库,那么这种情况会很常见。因此,更现实的是,在一个体面大小的程序中,有数千个额外的字符。据推测,“using”指令被添加到语言中,以便可以使用它......
5赞 DaveWalley 3/6/2014
它不是每次都额外 5 个字符,而是 5 个字符,可能只需单击几下鼠标即可下拉菜单并在您选择的编辑器中执行查找和替换。
1赞 oz1cz 10/24/2014
可读性。 比cout << hex << setw(4) << i << endl;std::cout << std::hex << std::setw(4) << i << std::endl;
18赞 oz1cz 10/24/2014
更糟糕的是:与.std::map<std::string,std::pair<std::string,std::string>>map<string,pair<string,string>>
4赞 juzzlin 1/19/2016
无论如何,最好对 STL 容器进行 typedef 处理,所以 std:: 真的没关系。C++11 为我们带来了 auto 关键字,这使得使用迭代器时变得更加容易。
6赞 Noneyo Getit 6/28/2013 #19

为了回答你的问题,我实际上是这样看的:很多程序员(不是全部)调用命名空间 std。因此,人们应该养成不使用与命名空间 std 中的内容相同的内容或使用相同名称的东西的习惯。这是一笔不小的数额,但与严格来说可以想出的可能连贯的单词和假名的数量相比,还算不上什么。

我的意思是真的......说“不要依赖它的存在”只是让你依赖它不存在。您经常会遇到借用代码片段并不断修复它们的问题。只需将用户定义和借用的东西保持在有限的范围内,并且非常谨慎地使用全局变量(老实说,出于“现在编译,以后健全”的目的,全局变量几乎总是最后的手段)。真的,我认为这是你老师的坏建议,因为使用 std 对“cout”和“std::cout”都有效,但不使用 std 只对“std::cout”有效。你不会总是足够幸运地编写你自己的所有代码。

注意:在你真正了解编译器的工作原理之前,不要过分关注效率问题。有了一点编码经验,你不必对它们了解太多,你就会意识到它们能够将好的代码概括成简单的东西。每一点都像你用 C 语言编写整个代码一样简单,好的代码只在它需要的程度上复杂。

评论

2赞 Toby Speight 5/23/2018
考虑到有多少人似乎不知道有用的标准库函数(例如,从中重新发明东西),想象同一个人可以可靠地避免这些标识符似乎有点牵强。查看您自己的代码,并告诉我您从未有过名为 .或 、 或 、更不用说所有尚未进入的标识符,当 C++35 问世时,它们会破坏您的代码......<algorithm>countdistancelogdestroylaunchvisitbetasamplemessagesclamperasecopymodulusleftstd
53赞 Oleksiy 8/29/2013 #20

我同意它不应该在全球范围内使用,但在本地使用并没有那么邪恶,就像在.下面是“C++ 编程语言”中的一个示例:namespace

namespace My_lib {

    using namespace His_lib; // Everything from His_lib
    using namespace Her_lib; // Everything from Her_lib

    using His_lib::String; // Resolve potential clash in favor of His_lib
    using Her_lib::Vector; // Resolve potential clash in favor of Her_lib

}

在此示例中,我们解决了由其组成引起的潜在名称冲突和歧义。

在那里显式声明的名称(包括通过 using 声明声明的名称,如 )优先于通过 using 指令 () 在另一个作用域中可访问的名称。His_lib::Stringusing namespace Her_lib

评论

0赞 Ol Sen 4/24/2021
有趣的是,大多数其他答案都忘记了仅使用大括号来定义命名空间的范围{..}
3赞 meupul 9/17/2013 #21

我认为本地全局使用应该取决于应用程序。

因为,当我们在本地使用库时,有时代码会一团糟。可读性会变低。

因此,只有当可能发生冲突时,我们才应该在本地使用库。

我不是一个更有经验的人。所以,如果我错了,请告诉我。

19赞 user2645752 11/9/2013 #22

同时使用多个命名空间显然是灾难的根源,但在我看来,使用 JUST 命名空间和仅命名空间没什么大不了的,因为重新定义只能通过您自己的代码进行......stdstd

因此,只需将它们视为保留名称,例如“int”或“class”,仅此而已。

人们应该停止对它如此肛门。你的老师一直都是对的。只需使用一个命名空间;这就是首先使用命名空间的全部意义所在。您不应同时使用多个。除非是你自己的。所以再说一次,重新定义不会发生。

评论

0赞 Tom Swirly 5/25/2016
创建冲突并不难 - 像 这样的短字符串出现在命名空间中。但更重要的是,现在它有成千上万的符号,读者知道他们可能不知道的新符号来自哪里是很有用的。minendlessstd::std::
0赞 Aiken Drum 8/23/2017
std 命名空间之所以存在,是因为人们,无论是你、你的同事,还是你使用的中间件编写者,并不总是明智地将函数放在命名空间中。因此,您可以导入所有 std:: 而不导入其他任何内容,同时仍然调用 std::min 和其他人的遗留 ::min() 之间的冲突,因为它在 std 中之前。
35赞 gnasher729 3/14/2014 #23

很高兴看到代码并知道它的作用。如果我看到,我知道那是图书馆的流。如果我看到,那我不知道。它可能是库的流。或者在同一函数中可能有 10 行。或者该文件中命名的变量。它可以是任何东西。std::coutcoutstdcoutcoutstdint cout = 0;staticcout

现在拿一百万行代码库来说,这并不是特别大,你正在寻找一个错误,这意味着你知道在这一百万行中有一行没有做它应该做的事情。 可以读取一个命名,将其向左移动一位,然后扔掉结果。寻找错误,我必须检查一下。你能看到我真正喜欢看到的样子吗?cout << 1;static intcoutstd::cout

如果您是一名教师并且从未以编写和维护任何代码为生,这似乎是一个非常好的主意。我喜欢看到代码:(1)我知道它的作用;(2)我相信写它的人知道它的作用。

评论

7赞 nyholku 6/11/2015
你怎么知道“std::cout << 1”不是在 std 命名空间中读取一个名为 cout 的静态 int 将其移动 1 并丢弃结果?另外,你怎么知道“<<”是什么;) ???...似乎这个答案不是避免“使用”的好数据点。
6赞 Jeremy Friesner 7/7/2016
如果有人将 std::cout 重新定义为整数,那么你的问题就不是技术问题,而是社会问题——有人为你解决了这个问题。(您可能还应该检查所有标头中是否存在诸如 #define true false 等内容)
6赞 Tien Do 8/31/2018
当我看到 cout 时,我知道它总是 std::cout。如果我错了,那是写这段代码的人的问题,而不是我的问题:)
8赞 user4138451 10/14/2014 #24

我同意其他人的观点——它要求名称冲突、模棱两可,然后事实是它不那么明确。虽然我可以看到 的用途,但我个人的偏好是限制它。我也会强烈考虑其他人指出的内容:using

如果你想找到一个函数名称,它可能是一个相当常见的名称,但你只想在命名空间中找到它(或者相反——你想改变所有不在命名空间、命名空间、...)中的调用,那么你打算如何做到这一点?stdstdX

你可以写一个程序来做这件事,但是花时间在你的项目本身上,而不是写一个程序来维护你的项目不是更好吗?

就个人而言,我实际上并不介意前缀。我喜欢这种外观,而不是没有它。我不知道这是否是因为它很明确,对我说“这不是我的代码......我正在使用标准库“,或者如果它是其他东西,但我认为它看起来更好。这可能很奇怪,因为我最近才开始接触 C++(使用并且仍然使用 C 和其他语言的时间要长得多,而 C 是我一直以来最喜欢的语言,就在汇编之上)。std::

还有一件事,尽管它与上述内容以及其他人指出的内容有些相关。虽然这可能是不好的做法,但我有时会保留标准库版本和名称,以便特定于程序的实现。是的,这确实会咬你,狠狠地咬你,但归根结底,我从头开始了这个项目,我是唯一的程序员。示例:我重载并调用它。我有有用的补充。我这样做的部分原因是我的 C 和 Unix (+ Linux) 倾向于使用小写名称。std::namestd::stringstring

除此之外,您还可以拥有命名空间别名。下面是一个示例,说明它可能没有被提及的有用之处。我使用 C++11 标准,特别是 libstdc++。好吧,它没有完整的支持。当然,它可以编译,但它会抛出一个异常,因为它是程序员端的错误。但这是缺乏执行力。std::regex

所以这是我解决它的方法。安装 Boost 的正则表达式,并将其链接进去。然后,我执行以下操作,以便当 libstdc++ 完全实现它时,我只需要删除此块,代码保持不变:

namespace std
{
    using boost::regex;
    using boost::regex_error;
    using boost::regex_replace;
    using boost::regex_search;
    using boost::regex_match;
    using boost::smatch;
    namespace regex_constants = boost::regex_constants;
}

我不会争论这是否是一个坏主意。然而,我会争辩说,它为我的项目保持干净,同时使它具体化:没错,我必须使用 Boost,但我使用它就像 libstdc++ 最终会拥有它一样。是的,从一开始就开始你自己的项目,从标准(...)开始,对帮助维护、开发和项目所涉及的一切有很长的路要走!

只是为了澄清一些事情:我实际上并不认为在 STL 中故意和更具体地使用类/任何东西的名称来代替是一个好主意。字符串对我来说是例外(忽略这里的第一个、上面或第二个,如果必须的话,双关语),因为我不喜欢“字符串”的想法。

事实上,我仍然非常偏向 C 和偏向 C++。撇开细节不谈,我所做的大部分工作都更适合 C(但这是一个很好的练习,也是让自己 a. 学习另一种语言和 b. 尽量不要对对象/类/等产生偏见的好方法,这可能更好地说成不那么封闭,不那么傲慢,更能接受。但有用的是一些人已经建议的:我确实使用列表(它相当通用,不是吗?),并排序(同样的事情)来命名两个,如果我这样做会导致名称冲突,因此为此,我更喜欢具体,控制并知道如果我打算将其作为标准用法,那么我将不得不指定它。简单地说:不允许假设。using namespace std;

至于使 Boost 的正则表达式成为 .我这样做是为了未来的整合,而且——我再次完全承认这是偏见——我不认为它像.事实上,这对我来说是另一回事。在 C++ 中,在外观和方法上,我仍然没有完全接受很多东西(另一个例子:可变模板与 var 参数 [尽管我承认可变模板非常有用!])。即使是那些我接受的人也很困难,我仍然对他们有疑问。stdboost::regex:: ...

评论

1赞 tambre 6/22/2018
扩展 std 命名空间是未定义的行为,因此永远不应该这样做。
239赞 mattnewport 11/4/2014 #25

短版本:不要在头文件中使用全局声明或指令。随意在实现文件中使用它们。以下是Herb SutterAndrei AlexandrescuC++编码标准中对这个问题的看法(粗体强调是我的):using

总结

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

推论:在头文件中,不要编写命名空间级别的 using 指令或 using 声明;相反,显式命名空间限定所有名称。(第二条规则遵循第一条规则,因为标头永远无法知道它们后面可能出现的其他标头 #includes。

讨论

简而言之:在 #include 指令之后,你可以而且应该在实现文件中自由地使用使用声明和指令的命名空间,并且对此感觉良好。尽管一再提出相反的断言,但使用声明和指令的命名空间并不是邪恶的,它们不会破坏命名空间的目的。相反,它们是使命名空间可用的原因

评论

15赞 dgnuff 2/24/2016
这里再说一个程序员的意见,但是虽然我 100% 同意这个词永远不应该出现在标题中的说法,但我并不相信将这个词放在代码中任何地方的免费许可证,特别是如果是.我使用表单,因为它只将单个元素从命名空间拉入伪全局范围,因此导致冲突的风险要小得多。usingusing namespace xyz;xyzstdusing std::vector;
6赞 CharonX 1/9/2020
我不禁觉得,邪恶就像邪恶一样。两者都有有效的用途,但 1000 次中有 999 次会被错误使用。所以,是的,在源代码中,你不会污染其他包含的命名空间,整洁。但它仍然不能保护你免受 + 带来的“乐趣”,你调用(隐式 Foo::) 突然代码破解(没有相关更改),只是因为被添加到某个地方,这恰好是一个更好的匹配(因此现在被调用)using namespacegotousing namespaceusing namespace Foousing namespace Barbaz(xyz)Bar::baz()
1赞 AdmiralAdama 9/29/2020
@CharonX 但是,只有当您的源文件(调用)实际上是声明的标头时,代码才会中断吗?似乎不太可能发生。这就像如果我在我的 main.cpp 文件中写入,但没有,那么我仍然可以在 main.cpp 中定义一个 fn,并且不会发生冲突。Foo::baz()#includeBar::baz()using namespace std;#include <iostream>cout
3赞 CharonX 10/8/2020
@AdmiralAdama 是的,当然需要包含该标头 - 但这可以间接完成(标头包括其他标头等)。所以这个错误是比较罕见的......但是当它发生时,它可能非常令人讨厌(你调用的函数会发生变化),很难检测到(通过在某处添加一个函数来触发,因此它发布的风险很高)并且很难追踪(代码“看起来”100% 正确)。我在软件工程的回答中给出了一个更详细的例子
0赞 Ben Voigt 4/2/2022
@AdmiralAdama:这是错误的,系统头文件被允许包含其他系统头文件,所以即使你没有,也可能在范围内,如果你现在编写,你的代码在某些平台上运行,在其他平台上中断,这取决于一个系统头是否包含另一个系统头的详细信息(注意,一个头文件足以, 一个标头,其存在的唯一目的是从其他标头中包含)#include <iostream>std::coutusing namespace std;#include <iosfwd>
13赞 Nithin 12/31/2014 #26

一个例子,由于计数的模糊性而抛出编译错误,这也是算法库中的一个函数。using namespace std

#include <iostream>
#include <algorithm>

using namespace std;

int count = 1;
int main() {
    cout << count << endl;
}

评论

3赞 Petr Skocik 7/12/2015
::count--问题解决了。通常,来自 std 命名空间的内容会比其他地方的内容更多,因此保留 using namespace 指令可能会节省您键入的内容。
0赞 Aiken Drum 8/23/2017
这里真正的问题是 C++ 仍然具有无命名空间的全局变量。这一点,以及“this”隐含在方法中的事实,导致了如此多的错误和问题,即使使用正确的“count”变量,我什至无法计算它们。;)
14赞 Carl 2/12/2015 #27

我同意这里的其他人,但我想解决有关可读性的问题 - 您可以通过简单地在文件、函数或类声明的顶部使用 typedefs 来避免所有这些问题。

我通常在我的类声明中使用它,因为类中的方法倾向于处理相似的数据类型(成员),而 typedef 是分配在类上下文中有意义的名称的机会。这实际上有助于类方法定义的可读性。

// Header
class File
{
   typedef std::vector<std::string> Lines;
   Lines ReadLines();
}

在实施中:

// .cpp
Lines File::ReadLines()
{
    Lines lines;
    // Get them...
    return lines;
}

与以下情况相反:

// .cpp
vector<string> File::ReadLines()
{
    vector<string> lines;
    // Get them...
    return lines;
}

艺术

// .cpp
std::vector<std::string> File::ReadLines()
{
    std::vector<std::string> lines;
    // Get them...
    return lines;
}

评论

0赞 iam3yal 3/11/2016
只是一个小评论,虽然 typedef 很有用,但我会考虑创建一个表示 Lines 的类,而不是使用 typedef。
14赞 Rohan Singh 4/5/2015 #28

命名空间是一个命名范围。命名空间用于对相关声明进行分组并保持独立 项目分开。例如,两个单独开发的库可能使用相同的名称来指代不同的 项,但用户仍可同时使用:

namespace Mylib{
    template<class T> class Stack{ /* ... */ };
    // ...
}

namespace Yourlib{
    class Stack{ /* ... */ };
    // ...
}

void f(int max) {
    Mylib::Stack<int> s1(max); // Use my stack
    Yourlib::Stack    s2(max); // Use your stack
    // ...
}

重复命名空间名称可能会分散读者和作者的注意力。因此,这是可能的 声明特定命名空间中的名称在没有显式限定的情况下可用。例如:

void f(int max) {
    using namespace Mylib; // Make names from Mylib accessible
    Stack<int> s1(max); // Use my stack
    Yourlib::Stack s2(max); // Use your stack
    // ...
}

命名空间为管理不同库和不同版本的代码提供了强大的工具。特别是,它们为程序员提供了如何显式引用非本地名称的替代方法。

来源:Bjarne Stroustrup的C++编程语言概述

评论

5赞 nyholku 6/11/2015
非常有趣的是,这个答案是基于 Bjarne Stroustrup 获得 -2 的指导......男孩 Bjarne 在将这个功能引入 C++ 时一定是一个贫穷且缺乏经验的程序员
0赞 sbi 8/5/2015
@nyholku:看这个
2赞 Martin G 8/15/2016 #29

以下示例显示了如何导致名称冲突问题:using namespace std;

无法在 C++ 中定义全局变量

在此示例中,一个非常通用的算法名称 () 名称与一个非常合理的变量名称 () 冲突。std::countcount

8赞 Engine Dev 8/21/2016 #30

根据我的经验,如果您有多个库使用 比如,,但出于不同的目的,您可能会使用错误的 .coutcout

例如,如果我输入 and 和 just 键入(恰好在两者中),而不是 (或 ),您可能会使用错误的,并出现错误。使用起来更有效和高效。using namespace std;using namespace otherlib;coutstd::cout'otherlib::cout'std::cout

24赞 Kevin 9/3/2016 #31

一个具体的例子来澄清这个问题。想象一下,你有两个库,每个库都有自己的命名空间:foobar

namespace foo {
    void a(float) { /* Does something */ }
}

namespace bar {
    ...
}

现在,假设您在自己的程序中使用 and,如下所示:foobar

using namespace foo;
using namespace bar;

void main() {
    a(42);
}

在这一点上,一切都很好。当你运行你的程序时,它会“做一些事情”。但后来你更新了,假设它已经变成了这样:bar

namespace bar {
    void a(float) { /* Does something completely different */ }
}

此时,你会得到一个编译器错误:

using namespace foo;
using namespace bar;

void main() {
    a(42);  // error: call to 'a' is ambiguous, should be foo::a(42)
}

因此,您需要进行一些维护以澄清“a”的含义。这是不可取的,但幸运的是,这很容易(只需在所有调用前面添加编译器标记为不明确)。foo::afoo::a

但是想象一下另一种情况,其中 bar 改为如下所示:

namespace bar {
    void a(int) { /* Does something completely different */ }
}

在这一点上,你的调用突然绑定到而不是做“某事”,而不是做“完全不同的事情”。没有编译器警告或任何东西。你的程序只是默默地开始做一些与以前完全不同的事情。a(42)bar::afoo::a

当您使用命名空间时,您冒着这样的情况的风险,这就是人们使用命名空间感到不舒服的原因。命名空间中的内容越多,发生冲突的风险就越大,因此人们使用命名空间(由于该命名空间中的内容数量)可能比其他命名空间更不舒服。std

归根结底,这是可写性与可靠性/可维护性之间的权衡。可读性也可能是因素,但我可以看到任何一种方式的论点。通常我会说可靠性和可维护性更重要,但在这种情况下,您将不断为相当罕见的可靠性/可维护性影响支付可写性成本。“最佳”权衡将决定您的项目和优先级。

评论

1赞 safe_malloc 11/5/2019
第二种情况为我达成了交易。再次没有命名空间。在引擎盖下,不可能有如此细微的功能变化而不被发现。
0赞 supercat 4/6/2021
解决该问题的方法是允许使用版本标记命名空间成员,并且具有一种方法,通过该方法,指令可以指定它应该引入使用旧版本号标记的成员,而不是使用较新版本号标记的成员。如果在程序员编写指令时,库的最新版本是 147,程序在 using 指令中包含该版本号,并且以后添加的任何函数都标有更高的数字,则指定版本 147 的代码将继续以与往常相同的方式工作。usingusing
1赞 m_highlanderish 6/7/2017 #32

这是我在任何其他答案中都没有找到的观点:只使用一个命名空间。根据大多数答案,命名空间不好的主要原因是,函数名称可能会发生冲突,这可能会导致一团糟。但是,如果仅使用一个命名空间,则不会发生这种情况。确定您将使用最多(也许)的库并坚持使用。using namespace std;

人们可以把它想象成一个不可见的库前缀 - 变得只是.在我看来,这是两全其美的:一方面,它减少了你必须做的输入量(正如命名空间所期望的那样),另一方面,它仍然需要你使用前缀来确保清晰和安全性。如果有一个没有命名空间前缀的函数或对象 - 你知道它来自你声明的一个命名空间。std::vectorvector

请记住,如果您决定在全球范围内使用一个 - 不要在本地使用其他。这又回到了其他答案,即本地命名空间通常比全局命名空间更有用,因为它们提供了多种便利。

4赞 Timon Paßlick 10/31/2017 #33

老实说,对我来说,这就像讨论缩进的空格数量。

在标头中使用指令会造成损坏。但是在 C++ 文件中呢?也许如果你同时使用两个命名空间。但如果你使用一个,它更多的是关于风格而不是真正的效率。

你知道为什么关于缩进的线程如此受欢迎吗?任何人都可以对此发表意见,听起来非常聪明和有经验。

评论

1赞 Kuba hasn't forgotten Monica 9/6/2020
只需要一个例子来证明一个对立点:编译时没有任何 NOR 在你的代码中。这是我在重构真实项目时遇到的一个真正的错误。 它充满了通用名称,以至于像这样的错误在许多商业代码库中都存在,其中原始值被分解,现在无效的使用仍然存在。这是源文件中的问题,而不是标头中的问题。这不是一个见仁见智的问题。只找一个常见的例子,其中产生了无声的错误,游戏就结束了。禁止这些东西。if (left != right)using std::namespace;leftrightstd.cpp
0赞 Timon Paßlick 9/6/2020
公平地说,我在写这个答案时没有考虑到这一点。
0赞 Secundi 12/16/2020
在 cpp-Files 中:您可能会惊讶于 UnityBuilds 在这里会发生什么......它们并不少见......
7赞 adn.911 12/1/2017 #34

这是一种不好的做法,通常称为全局命名空间污染。当多个命名空间具有相同的函数名称和签名时,可能会出现问题,然后编译器决定调用哪一个是模棱两可的,当您使用函数调用指定命名空间时,可以避免这种情况,例如 .希望这会有所帮助。:)std::cout

11赞 CryogenicNeo 4/24/2018 #35

它不会使您的软件或项目性能变差。在源代码的开头包含命名空间还不错。说明的包含范围根据您的需求以及您开发软件或项目的方式而有所不同。using namespace std

包含 C++ 标准函数和变量。当您经常使用 C++ 标准函数时,此命名空间非常有用。namespace std

如本所述:

使用命名空间 std 的语句通常被认为是错误的 实践。此语句的替代方法是指定 标识符所属的命名空间,使用作用域运算符 (::) 每次我们声明一个类型。

并看到这个意见

在源文件中使用“using namespace std”没有问题 当您大量使用命名空间并确定 没有什么会碰撞。

有些人说,在源文件中包含 是一种不好的做法,因为你是从该命名空间调用所有函数和变量。当您想要定义一个与中包含的另一个函数同名的新函数时,您将使该函数重载,并且可能会因编译或执行而产生问题。它不会按预期编译或执行。using namespace stdnamespace std

如本所述:

尽管该语句使我们不必键入 std:: 每当 我们希望访问 std 命名空间中定义的类或类型,它 将整个 std 命名空间导入到当前命名空间中 的程序。让我们举几个例子来理解为什么会这样 可能不是一件好事

...

现在在开发的后期阶段,我们希望使用另一个版本的 cout 在某个名为“foo”的库中自定义实现(用于 示例)

...

请注意,cout 指向哪个库存在歧义? 编译器可能会检测到这一点,但不会编译程序。在最坏的情况下 情况下,程序可能仍会编译但调用错误的函数,因为 我们从未指定标识符属于哪个命名空间。

11赞 Swiss Frank 5/23/2019 #36

这是个案。我们希望在软件的整个生命周期内将“总拥有成本”降至最低。声明“使用命名空间标准”有一些成本,但不使用它也会在易读性方面产生成本。

人们正确地指出,在使用它时,当标准库引入新的符号和定义时,您的代码会停止编译,您可能会被迫重命名变量。然而,从长远来看,这可能是件好事,因为如果你将一个关键词用于一些令人惊讶的目的,未来的维护者会暂时感到困惑或分心。

比如说,你不希望有一个名为 vector 的模板,它不是其他人都知道的向量。因此,在 C++ 库中引入的新定义数量很少,可能根本无法出现。必须进行这种更改是成本的,但成本并不高,并且可以通过不将符号名称用于其他目的而获得的清晰度来抵消。std

考虑到类、变量和函数的数量,对每个类、变量和函数进行说明可能会使你的代码增加 50%,并使你更难理解。现在可以在一个代码屏幕上采用的算法或方法中的步骤现在需要来回滚动才能跟随。这是一个真正的成本。可以说,它可能不是一个高昂的成本,但否认它存在的人是缺乏经验的、教条主义的,或者干脆是错误的。std::

我会提供以下规则:

  1. std与所有其他库不同。它是每个人都需要知道的一个库,在我看来,最好将其视为语言的一部分。一般来说,即使没有其他库,也有一个很好的案例。using namespace std

  2. 切勿将此决定强加给编译单元(.cpp文件)的作者,方法是将其放在标题中。始终将决定权交给编译单元作者。即使在一个决定到处使用的项目中,也可能会罚款一些模块,这些模块最好作为该规则的例外处理。usingusing namespace std

  3. 尽管命名空间功能允许您拥有许多定义相同符号的模块,但这样做会令人困惑。尽可能保持名称不同。即使不使用命名空间功能,如果您有一个名为的类并引入了一个名为 的类,那么从长远来看,重命名您的类可能更好。foostdfoo

  4. 使用命名空间的替代方法是通过在符号前面添加前缀来手动设置命名空间符号。我有两个库,我已经使用了几十年,实际上都是从 C 库开始的,其中每个符号都以“AK”或“SCWin”为前缀。一般来说,这就像避免使用“使用”结构,但你不写双冒号。 是 .它使代码的密度提高了 5-10%,并且不那么冗长,唯一的缺点是,如果您必须使用两个具有相同前缀的此类库,您将遇到大麻烦。请注意,X Window 库在这方面非常出色,只是它们忘记了这样做的一些 #defines:TRUE 和 FALSE 应该是 XTRUE 和 XFALSE,这设置了与 Sybase 或 Oracle 的命名空间冲突,后者同样使用具有不同值的 TRUE 和 FALSE!(在数据库的情况下为 ASCII 0 和 1!这样做的一个特殊优点是它完美地应用于预处理器定义,而 C++ / 系统不处理它们。这样做的一个很好的好处是,它提供了一个有机的斜坡,从成为项目的一部分到最终成为一个图书馆。在我的一个大型应用程序中,所有窗口类都带有前缀,所有信号处理模块都是 Mod,等等。这些中的任何一个都不太可能被重用,因此将每个组变成一个库没有实际的好处,但它在几秒钟内就清楚地表明了项目如何分解为子项目。AK::foo()AKFoo()usingnamespaceWin

评论

1赞 Ingo Mi 12/3/2019
最后,谢谢!节省您编写的每个代码的时间,而不是“可能”修复遗留代码的时间,至少使用 std 库。
5赞 Brett Hale 2/28/2020 #37

答案很简单:这是防御性编程。您知道 、 等的使用可以变得更容易一些 - 我希望您不需要确信这样的指令在标头中没有位置!然而,在翻译单元中,您可能会受到诱惑......std::size_tstd::coutusing namespace std;

命名空间中的类型、类等会随着每个 C++ 修订而增加。如果放宽限定符,则有太多潜在的歧义。放宽您将经常使用的名称的限定符是完全合理的,例如,,或者更可能的内容: - 但除非这些已经是语言中很好理解的部分(或者具体来说,是 C 库的包装),否则只需使用限定符。stdstd::stdusing std::fprintf;using std::size_t;std

当您可以将 、与 和 推理结合使用时,从可读性/可维护性的角度来看,实际上没有任何收获。typedefautodecltype

5赞 Kuba hasn't forgotten Monica 5/22/2020 #38
#include <iostream>

using namespace std;

int main() {
  // There used to be
  // int left, right;
  // But not anymore

  if (left != right)
    std::cout << "Excuse me, WHAT?!\n";
}

那么,为什么呢?因为它引入了与常用变量名称重叠的标识符,并让这段代码编译,将其解释为 .if (std::left != std::right)

PVS-Studio 可以使用 V1058 诊断程序找到此类错误:https://godbolt.org/z/YZTwhp(谢谢 Andrey Karpov!!

Ping cppcheck 开发人员:您可能希望标记此。这真是昏昏欲睡。

3赞 Akib Azmain Turja 9/21/2020 #39

命名空间是为了避免命名冲突。C++ 基于 C,C 在函数和变量名称方面存在许多问题,因为有时来自不同库的函数会发生冲突。因此,库开发人员开始在他们的函数前面加上库名称,如下所示:

foo/foo.h

void libfoo_foo_foo_h_open(); // the name can be weird then even this one!

C++引入了命名空间来以简单的方式解决这个问题。

假设您有两个名为 和 分别处理文件和窗口的库,以及以下代码:filewindow

#include <file.h>
#include <window.h>

using namespace file;
using namespace window;

void open() {
     ...
}

file.h

namespace file {
    void open(); // What!
}

window.h

namespace window {
    void open(); // Oh no!
}

上面的代码肯定会编译失败。

如果您不喜欢类型(只有 5 个字符),您可以随时这样做:(在头文件中不是一个好主意)std::

using s = std;

如果你仍然想在你的源文件中使用,那么你就邀请了这个问题,我必须问你“命名空间的目的是什么?using namespace std;

1赞 Muhammad Ali 10/19/2021 #40

为什么使用命名空间标准?

C++ 有一个标准库,其中包含您在构建应用程序(如容器、算法等)时使用的常见功能。如果这些名称是公开的,例如,如果它们全局定义了一个队列类,则您将永远无法再次使用相同的名称而不会发生冲突。因此,他们创建了一个命名空间 std 来包含此更改。

不使用的原因 1:不良做法

使用 namespace std 的语句通常被认为是不好的做法。此语句的替代方法是在每次声明类型时使用作用域运算符 (::) 指定标识符所属的命名空间。尽管该语句使我们在希望访问 std 命名空间中定义的类或类型时不必键入 std::,但它会将整个 std 命名空间导入到程序的当前命名空间中。

不使用的原因 2:编译器感到困惑

在玩具程序中导入整个 std 库是可以的,但在生产级代码中,这很糟糕。使用命名空间 std;使命名空间 std 中声明的每个符号都可以在没有命名空间限定符的情况下访问。

例如:

现在,假设您升级到较新版本的 C++,并且将更多您不知道的新 std 命名空间符号注入到您的程序中。您可能已经在程序中使用了这些符号。现在,编译器将很难弄清楚声明的符号是属于您自己的实现,还是来自您导入的命名空间,而无需任何想法。某些编译器会引发错误。如果你运气不好,编译器选择了错误的实现并编译它,这肯定会导致运行时崩溃。

命名空间污染影响:

虽然这种做法对于示例代码来说是可以的,但将整个 std 命名空间拉入全局命名空间并不好,因为它违背了命名空间的目的,并可能导致名称冲突。这种情况称为命名空间污染。

评论

1赞 Muhammad Ali 10/19/2021
阅读:dev.to/77bala7790/......
-3赞 uuu777 1/14/2022 #41

只要你不在头文件中使用'using namespace std',它应该是完全正常的。

如果与 boost 存在命名冲突,则不要在特定的 .cpp 文件中使用此语句,但仍然可以通过不在其他文件的每一行上重复“std::” 十次来节省每个人的眼睛和手指。

不幸的是,现在这是一个纯粹的宗教问题,每个人都更容易/更有成效地遵循一遍又一遍地重复“std::”的既定模式。

评论

0赞 hyde 2/19/2022
“纯粹的宗教问题”,除了许多其他答案中列出的所有非常实际的原因......至少,这个答案应该另外提供问题的解决方案,例如标准名称空间使用新的 C++ 标准版本获取新符号。
5赞 Muhammad Ali 3/24/2023 #42

为什么要避免使用命名空间 std;

原因一:为避免名称冲突。

由于 C++ 标准库很大且不断扩展,因此 C++ 中的命名空间用于减少名称冲突。当您使用“using namespace std;”时,您正在批量导入所有内容。

这就是为什么“using namespace std;”永远不会出现在任何专业代码中的原因。

原因二:编译失败。

因为它将 std 命名空间中定义的数百个事物(类、方法、常量、模板等)拉取到全局命名空间中。它这样做,不仅适用于写入“using namespace std”本身的文件,还适用于递归包含它的任何文件。这很容易导致意外的 ODR 违规和难以调试的编译器/链接器错误。

例:

在全局命名空间中声明函数“max”时,请使用 std 命名空间。

由于您没有使用 cmath 标头,因此一切似乎都运行良好。

当其他人包含您的文件和 cmath 标头时,他们的代码意外无法生成,因为全局命名空间中有两个名为“max”的函数。

原因 3:将来可能不起作用。

更糟糕的是,您无法预测将来会对 std:: 命名空间进行哪些更改。这意味着,如果新添加的符号与代码中的某些内容发生冲突,则今天运行的代码以后可能会停止运行。

原因四:维护调试难度大。

使用命名空间 std;可能会产生难以维护和难以调试的代码。这是因为某些方面的来源并不总是很明显。如果开发人员使用术语“string”而不进行更多解释,则他们可能会引用 std::string 类或唯一的字符串类。


命名空间为 std 的代码

#include <iostream>
#include <algorithm>

using namespace std;

int swap = 0;

int main() {
    cout << swap << endl; // ERROR: reference to "swap" is ambiguous
}

不带命名空间

#include <iostream>

int main() {
    using std::cout; // This only affects the current function

    cout << "Hello" <<'\n';
}

但是你可以使用如果,

  • 如果您想制作简短的教程或程序等,您可以使用它。

  • 当您大量使用命名空间并确定不会发生冲突时,在源文件中使用“使用命名空间标准”没有问题。