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

问:

我听说 using namespace std; 是不好的做法,我应该直接使用 std::cout 和 std::cin。为什么是这样?是否冒着声明与 std 命名空间中的某些东西同名的变量的风险?

答1:

huntsbot.com精选全球7大洲远程工作机会,涵盖各领域,帮助想要远程工作的数字游民们能更精准、更高效的找到对方。

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

using namespace foo;
using namespace bar;

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

如果您使用了 foo::Blah() 和 bar::Quux(),那么 foo::Quux() 的引入就不会发生。

我一直很喜欢 Python 的“import big_honkin_name as bhn”,所以你可以只使用“bhn.something”而不是“big_honkin_name.something”——真的减少了打字。 C++有类似的东西吗?

@Pax 命名空间 io = boost::filesystem;

我认为说这是“一些努力修复”是夸大其词。您将没有新的 foo::Quux 的实例,因此只需使用 bar::Quux 消除所有当前使用的歧义。

任何明智的人会创建一个其非限定名称与 std 类型冲突的类型的库吗?

@erikkallen:std lib 采用了数百个(甚至数千个)名称,其中许多非常流行和常见(error、list、sort),IIRC 是放置它的一个重要原因进入自己的命名空间。

答2:

与HuntsBot一起,探索全球自由职业机会–huntsbot.com

情况可能会变得更糟,比Greg wrote更糟!

Library Foo 2.0 可以引入一个函数 Quux(),它对于您对 Quux() 的某些调用而言无疑比您的代码多年来调用的 bar::Quux() 更匹配。然后你的代码仍然可以编译,但是它默默地调用了错误的函数并且天知道了。这几乎是最糟糕的事情了。

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

如果您认为这不太可能:在我给出这个答案大约半年后,Stack Overflow 上的 a question asked 几乎完全发生了这种情况(由于省略了 std:: 前缀而调用了错误的函数)。 Here 是此类问题的另一个较新的示例。所以这是一个真正的问题。

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

十年后,该项目发展到拥有数百万行代码。由于这些讨论一次又一次地出现,我曾经很好奇(允许的)函数范围 using 在项目中实际使用的频率。我搜索了它的来源,只找到了一两打使用它的地方。对我来说,这表明,一旦尝试,即使在允许使用的地方,即使每 100 kLoC 使用一次,开发人员也不会觉得 std:: 痛苦到足以使用 using 指令。

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

不同意读者对 foo::bar() 的解释可能意味着来自命名空间 foo 的函数 bar 或来自类 foo 的静态函数。

@convert 为什么有人会调用类 foo 而不是 Foo?静态方法也应该称为 Foo::Bar 而不是 Foo::bar。这就是为什么人们认为约定是一件好事。

@convert 这是标准库中的常见做法。大多数(我所知道的)C++ 编码约定都推荐大写的类。我所知道的超过一半的约定都推荐大写的静态方法。即使您有一些既不符合要求的巫毒编码约定,将 foo::bar 作为静态方法仍然不是反对解释点的论据。该函数/方法所属的位置仍然更清楚,如果您给您的类起一个好名字,那么仍然很清楚是一个类而不是命名空间。

@convert 是的,这正是我要说的。我的意见可能对你没有什么价值,但这甚至是 Stroustrups 和 Sutters 的意见:C++ Core Guidelines - 顺便说一句。我们应该停止用这个 12.5 岁的答案玩死灵法师......

@convert:“停止玩死灵法师”这不是聊天框,也不是组织节日的论坛,日历时间本身就是一个因素。这是一个知识库,其中仅日期无关紧要,相关性和一致性等问题很重要。这个话题(问题)既有答案,也有答案。所以,“我们应该停止”误解 SO 是什么。 (注意:您实际上在这里得到了奖励,以一种有用的方式更新旧项目。)

答3:

保持自己快人一步,享受全网独家提供的一站式外包任务、远程工作、创意产品订阅服务–huntsbot.com

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

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

请注意,有些人不同意我这样说“随意”——因为尽管 cpp 文件中的 using 语句比标题中的更好(因为它不会影响包含你的头文件),他们认为它仍然不是好(因为根据代码,它可能会使类的实现更难维护)。 This C++ Super-FAQ entry 说,

using 指令适用于遗留 C++ 代码并简化向命名空间的转换,但您可能不应该定期使用它,至少不要在新的 C++ 代码中使用它。

常见问题解答提出了两种选择:

使用声明: using std::cout; // using-declaration 允许您使用 cout 没有限定 cout << “Values:”;

只需输入 std:: std::cout << “Values:”;

当然,您也不应该假设全局 cout 的状态,以免有人拥有 std:cout << std::hex 并且事后 std::restore_cout_state 失败。但那完全是另一个胖子。

“但是,您可以随意在您的(私有)*.cpp 文件中添加 using 语句。”如果未来的开发团队决定更改翻译单元方案,例如通过 UnityBuilds 怎么办?毫无疑问,您最终会遇到可怕的未定义行为。

虽然对头文件的担忧是有道理的,但由于包含的方式可能会产生副作用,我觉得它们不适用于 cpp 文件。让我们看看几乎所有其他编程语言都会发生什么。例如,当您在 Java 中编码时,您几乎总是从您使用的包中导入每个符号——尤其是标准包。这意味着您几乎永远不会期望 String、List、Map 等的竞争和冲突实现。我知道的其他语言也会发生同样的情况。这是合理的国际海事组织,我们应该让生活变得轻松而不是艰难。

如果一个团队迁移到统一构建,它将不得不删除 using 关键字并哭泣,因为使用 stdlib 而不使用是一种痛苦。但是,如果您依赖 Qt,这没关系,因为 Qt 不使用命名空间(祝福他们)。尽管如此,统一构建是一个边缘案例。

…给你。另一方面,对于 C++ 生态系统的绝大多数人,包括 C++ 委员会、经验丰富的 C++ 开发人员的共同智慧和 C++ 语言的创造者本人,这不仅是一种选择,而且是推荐的选择。

答4:

huntsbot.com精选全球7大洲远程工作机会,涵盖各领域,帮助想要远程工作的数字游民们能更精准、更高效的找到对方。

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

using namespace std;
using namespace boost;

很多 Boost 功能正在进入 C++0x 标准,而 Visual Studio 2010 有很多 C++0x 功能,所以突然这些程序无法编译。

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

这个。 Boost 和 std 有很多重叠 - 特别是从 C++11 开始。

我这样做过一次,并以艰难的方式吸取了教训。现在,我从不在函数定义之外使用 using,也很少使用 using namespace。

我个人永远不会使用 boost,因为它是我见过的最糟糕的 C++ API。如果使用命名空间标准,我还会遇到哪些问题?

@convert 理论上任何库现在或将来都可能与 std 发生冲突。如其他答案中所述,std 包含许多常用名称,例如列表和错误。 Boost 只是突出了这个问题,因为它现在受到了影响。调用 using 撤消了应该修复的命名空间。小心它。

答5:

huntsbot.com全球7大洲远程工作机会,探索不一样的工作方式

短版:不要在头文件中使用全局 using 声明或指令。随意在实现文件中使用它们。以下是 Herb Sutter 和 Andrei Alexandrescu 在 C++ Coding Standards 中对这个问题的看法(粗体表示强调是我的):

总结 命名空间使用是为了您的方便,而不是让您强加于他人:切勿在#include 指令之前编写 using 声明或 using 指令。推论:在头文件中,不要写命名空间级别的 using 指令或 using 声明;相反,明确命名空间限定所有名称。 (第二条规则从第一条开始,因为标头永远无法知道其他标头#includes 可能出现在它们之后。) 讨论简而言之:您可以并且应该在#include 指令之后的实现文件中自由地使用命名空间使用声明和指令,并且感觉很好。尽管反复断言相反,使用声明和指令的命名空间并不是邪恶的,它们不会破坏命名空间的目的。相反,它们使命名空间可用。

这里只是另外一位程序员的意见,但虽然我 100% 同意 using 一词不应出现在标题中的说法,但我并不相信将 using namespace xyz; 放置在代码中任何位置的免费许可,尤其是如果 xyz 是 std。我使用 using std::vector; 形式,因为它只会将命名空间中的单个元素拉入伪全局范围,因此导致冲突的风险要小得多。

@Lightness Races in Orbit 你当然有权发表你的意见。如果有人尝试解释您为什么不同意此答案中给出的建议,那会更有帮助。如果“使用”名称空间不好,那么了解名称空间的意义尤其重要?为什么不将事物命名为 std_cout 而不是 std::cout ... C++/命名空间的创建者在他们费心创建它们时一定有一些想法。

@nyholku:不需要-其他大多数答案都给出了与我相同的原因。另外请不要犹豫,注意我在评论中附加的“:)”!而且我没有说命名空间不好。

我不禁觉得using namespace是邪恶的,就像goto是邪恶的一样。两者都有有效的用途,但 1000 次中有 999 次会被错误地使用。所以,是的,在源代码中使用 using namespace 您不会污染其他包含的命名空间,整洁。但它仍然不能保护您免受 using namespace Foo + using namespace Bar 引起的 "fun" 与您调用 (implicit Foo::) baz(xyz) 并突然代码中断(没有相关更改)只是因为 Bar::baz() 被添加到某处,恰好是一个更好的匹配(因此现在被调用)

@AdmiralAdama 是的,当然需要包含该标头-但这可以间接完成(标头包括其他标头等)。所以这个错误是比较罕见的......但是 当 它发生时它可能非常讨厌(你调用的函数发生变化),很难检测到(通过添加一个函数来触发 somewhere< /i>,所以它发布的风险很高)而且很难追踪(代码“看起来”100% 正确)。我在 answer over at software engineering 中给出了更详细的示例

答6:

huntsbot.com – 高效赚钱,自由工作

不应在全局范围内使用 using 指令,尤其是在标头中。但是,在某些情况下,即使在头文件中也是合适的:

template  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));
}

这比显式限定(std::sin、std::cos…)要好,因为它更短并且能够处理用户定义的浮点类型(通过 argument-dependent lookup (ADL))。

@Billy:没有其他方法可以支持调用 userlib::cos(userlib::superint)。每个功能都有用处。

@Zan:当然有。 using std::cos; 、 using std::sin 等。但问题是任何设计良好的 userlib 都将在其自己的命名空间中拥有它们的 sin 和 cos,因此这对您确实没有帮助。 (除非在这个模板之前有一个 using namespace userlib 并且它和 using namespace std 一样糟糕 - 并且范围没有限制。)此外,我见过的唯一这样的函数是 swap,并且在在这种情况下,我建议只创建 std::swap 的模板特化并避免整个问题。

@BillyONeal:template void swap(MyContainer&, MyContainer&)(没有函数模板部分专业化(FTPS),所以有时您需要求助于重载。

@BillyONEal:您的(7 次赞成!)评论是错误的——您描述的情况正是 ADL 旨在涵盖的内容。简而言之,如果 x 有一个或多个“关联命名空间”(例如,如果它在 namespace userlib 中定义),那么任何看起来像 cos(x) 的函数调用都会另外查看这些命名空间—— 无需事先任何using namespace userlib;。 Zan Lynx 是对的(C++ 名称查找是拜占庭式的......)

而不是 using namespace std;,我更喜欢 using std::sin; using std::cos; using std::exp;。您可以获得相同的好处,而没有将 std::* 倾倒到函数中的任何风险。

答7:

huntsbot.com – 高效赚钱,自由工作

不要全局使用

只有在全局使用时才被认为是“坏的”。因为:

你把你正在编程的命名空间弄得乱七八糟。

当您使用许多 using namespace xyz; 时,读者将很难看到特定标识符的来源。

对于你的源代码的其他读者来说是正确的,对于它最常见的读者来说更是如此:你自己。一两年后回来看看…

如果你只谈论 using namespace std;您可能不知道您抓取的所有内容 - 当您添加另一个 #include 或移动到新的 C++ 修订版时,您可能会遇到您不知道的名称冲突。

您可以在本地使用它

继续并在本地(几乎)自由使用它。当然,这会阻止您重复 std:: - 而且重复也很糟糕。

在本地使用它的成语

在 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(...)`
}

这具有以下魔力:

编译器将为 value_ 选择 std::swap,即 void std::swap(int, int)。

如果您实现了重载 void swap(Child&, Child&),编译器将选择它。

如果您没有该重载,编译器将使用 void std::swap(Child&,Child&) 并尽力交换这些。

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

“std::swap 的实现被改变以找到潜在的重载并选择它。” - 什么?您确定吗?尽管在 C++11 中提供自定义 swap 确实不再那么重要,因为 std::swap 本身更灵活(使用移动语义)。但是 std::swap 会自动选择您自己的自定义交换,这对我来说绝对是新事物(而且我不太相信)。

@ChristianRau 我想是的,是的。我在某处读到了这个。我们可以随时问Howard,他应该知道。我现在是 digging 和 digging...

即使在交换的情况下,更清晰(谢天谢地更常见)的习惯用法是写 using std::swap; 而不是 using namespace std;。更具体的习语具有更少的副作用,因此使代码更易于维护。

最后一句话是错的。在 C++11 中,Std Swap Two Step 被正式祝福为调用 swap 的正确方式,并且标准中的许多其他地方都被更改为这样调用 swap(注意为如上所述,using std::swap 是正确的方式,而不是 using namespace std)。但是 std::swap 本身被强调没有更改为找到其他一些 swap 并使用它。如果调用 std::swap,则使用 std::swap。

不过,在本地键入 using std::swap 可能更明智,以减少本地命名空间,同时创建自记录代码。您很少对整个 std 命名空间感兴趣,因此只需挑选出您感兴趣的部分。

答8:

huntsbot.com全球7大洲远程工作机会,探索不一样的工作方式

如果您导入正确的头文件,您的全局范围内会突然出现 hex、left、plus 或 count 之类的名称。如果您不知道 std:: 包含这些名称,这可能会令人惊讶。如果您还尝试在本地使用这些名称,可能会导致一些混乱。

如果所有标准的东西都在它自己的命名空间中,那么您不必担心与您的代码或其他库的名称冲突。

+1 更不用说distance了。在实际可行的情况下,我仍然更喜欢非限定名称,因为这增加了我的可读性。另外,我认为我们通常不会在口头演讲中对事物进行限定,并且愿意花时间解决可能的歧义,这意味着能够理解一个人在没有限定条件的情况下谈论的内容是有价值的,并将其应用于源代码意味着它的结构使得即使没有资格也很清楚它的全部内容。

不过,公平地说,如果您不包括 ,您就不会有其中的大部分。不过,好点。

@einpoklum 您通常不必包含 即可获得这些。对于前 gcc.godbolt.org/z/Kqx9q1 的 GCC 中的所有人来说,包括 就足够了

很确定您只需要 来获取带有参数的操纵器,例如 setw。

答9:

huntsbot.com洞察每一个产品背后的需求与收益,从而捕获灵感

另一个原因是惊喜。

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

你在开玩笑吗?我真的说不出来。如果不是,那么我个人会认为这是正常的“cout”,除非您不信任该代码,否则这将是一种 BEYOND MAJOR 代码气味,IMO。 ...如果您不信任该代码,那么您为什么首先使用它?请注意,我不是说“信任一切!!”但是,如果您正在处理一些来自 GitHub 的知名库或其他东西,这似乎也有点牵强。

@BrentRittenhouse cout 是一个不好的例子,因为每个人都承认它。但想象一下金融应用程序中的 future。是否是在指定日期买卖某物的合同?不,不是。如果代码是 std::future,你就不会那么容易混淆了。

@BrentRittenhouse 可能是一个不好的例子,至少有四个不同的库有 cout。可能是“它是标准库吗?libstdc++?stl?还有别的吗?”不,不是每个人都知道 std::cout,至少在本质上,我们收到的 7 名新员工中有 6 名不知道。因为教育课程不使用教育课程。我必须赶走printfs。或 debugs() - 来自 Qt。

真的吗?它几乎在很多关于 C++ 的书籍的第一章的第一个示例中,如果有的话,它(使用插入运算符)是一些新成员知道的唯一 C++。

@mckenzm 我可能会把它放在一本书或讲义中以减少混乱,但不会放在代码中

答10:

huntsbot.com精选全球7大洲远程工作机会,涵盖各领域,帮助想要远程工作的数字游民们能更精准、更高效的找到对方。

有经验的程序员使用任何可以解决他们的问题的方法并避免任何产生新问题的方法,并且出于这个确切原因,他们会避免使用头文件级别的使用指令。

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

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

所以以下是可以的:

函数实现中的函数级 using-directives 和 using-declarations 源文件中的源文件级 using-declarations(有时) 源文件级 using-directives

答11:

huntsbot.com – 程序员副业首选,一站式外包任务、远程工作、创意产品分享订阅平台。

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

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

}

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

在那里显式声明的名称(包括使用 His_lib::String 等使用声明声明的名称)优先于使用指令(using namespace Her_lib)在另一个范围内可访问的名称。

有趣的是,大多数其他答案如何忘记仅使用大括号 {..} 来定义命名空间的范围

原文链接:https://www.huntsbot.com/qa/5DwE/why-is-using-namespace-std-considered-bad-practice?lang=zh_CN&from=csdn

huntsbot.com汇聚了国内外优秀的初创产品创意,可按收入、分类等筛选,希望这些产品与实践经验能给您带来灵感。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值