什么是“使用命名空间”污染?


15

我在看[这里]的Google编码指南,他们不建议您使用using namespacenamespace::function-如果我没有误解的话。

这也适用std吗?cout<<没有它是行不通的。本书,推荐相同。那么,如何去使用cout<<没有using namespace std;std::cout<<

推荐的方法是什么?std::cout<<?大多数C ++教科书都向初学者讲授错误的using namespace std;编码实践吗?

Answers:


18

当我阅读Google标准时,您无法在using namespace foo;任何地方使用该指令。该指令引入了在命名空间中声明的所有内容,并且是冲突和意外行为的常见原因。其他人引用了一个非常常见的方法:您在某个地方有自己的max或min方法,并且它碰撞到src文件中,其中有人在您的方法中包含标头,然后说using namespace std;

在某些地方,允许使用using声明,其形式为 using ::foo::bar;

人们喜欢在代码中使用指令,因为它可以节省大量的键入操作,但存在风险。如果您的文件中包含很多cout语句,我可以理解,不想键入std :: cout一百次,但是您可以简单地说::: std :: cout。我将它们视为变量声明:将它们放在需要的地方。如果文件10中的一个函数需要写输出,则不要在顶部声明cout方式,而应将其放在执行实际输出的那个函数中。

#include <ostream>
//using namespace std; // NO!
//using ::std::cout;   // less bad than using namespace, but I prefer to scope it

int main(int argc, char** argv)
{
   int rc = do_some_stuff(argc, argv);
   using ::std::endl;
   if (rc) { // print the success report
      using ::std::cout;
      cout << "The test run completed. The return code was " << rc << '.' << endl;
    } else {
      using ::std::cerr;
      cerr << "Unable to complete the test run." << endl;
    }
    return 0 == rc;
}

只有几行输出,这有点极端,但是您明白了。

可以做的另一件事是别名或typedef以最大程度地减少键入。我没有发现std :::那样糟糕,但是我们拥有大量的源代码,其中包含数十个模块,有时我们必须编写类似的代码console_gui::command_window::append("text")。一段时间后,这变得很乏味,并导致很多行。我全都喜欢

typedef console_gui::command_window cw;
cw::append("text");

只要别名是在本地范围内完成的,并且保留足够的上下文以使代码可读即可。


1
谢谢!这真的很有帮助。您不仅通过精美的例子解释了为什么不好,而且还通过精美的例子指出了解决方案。:-)
卢勋爵。

1
顺便说一句:std::endlstdout/ 上进行显式刷新stderr通常是多余的,无论如何,这些流都绑定到stdout/ stderr。它甚至使速度变慢。
Deduplicator

8

这是因为:1)它破坏了名称空间的全部目的,即减少名称冲突。2)它使使用using指令指定的整个名称空间可用于全局名称空间。

例如,如果您包含并定义了自己的max()函数,它将与std :: max()冲突。

http://en.cppreference.com/w/cpp/algorithm/max

首选项是使用std :: member_you_wish_to_use,因为它明确指出要使用的命名空间。


我认为这意味着我应该使用std::max()名称空间前缀。还是我弄错了?
卢勋爵。

3
这意味着如果您放置“ using namespace std;” 在您的代码中,如果您定义自己的max函数(或在std名称空间中已定义的任何其他名称),则会收到错误消息
Chewy Gumball 2014年

1
这只是意味着您应该小心使用using指令,因为在这种情况下,如果您定义了一个指令并包含<algorithm>,它将破坏max()函数。这是一个简单的案例,但是您永远都不知道可能会破坏什么。您需要了解整个库,以确保您没有破坏它,但是您不知道您的代码将来是否会破坏(即名称冲突)。
ApplePie 2014年

6

引用您提供的链接:

您可以在.cc文件中的任何位置以及.h文件中的函数,方法或类中使用using-声明。

//在.cc文件中可以。

//必须位于.h文件中的函数,方法或类中。

使用:: foo :: bar;

Google样式禁止您在全局环境中使用导入名称空间,但允许在本地环境中使用。

在任何地方使用声明只会影响代码的有限且清晰可见的部分,这是完全可以接受的。

当您污染全局上下文时,不相关的代码会受到影响(使用标头的隐含行为)。在本地情况下,什么也不会发生。


我们有相同的标准。我们中的某些人会在本地对长名称空间进行typedef。例如:typedef foolicious :: barlicious fb; fb :: drink d;
Michael Mathews 2014年

1

他们不建议您使用using名称空间ornamespace:function`-如果我没有误解的话。

你做到了 不推荐仅适用于using namespace指令(通常称为abusing namespace,并非完全幽默)。强烈建议您使用函数或对象的完全限定名称,例如std::cout


1

尽管这个问题已经有了有用的答案,但其中一个细节似乎太短了。

大多数程序员起初对using关键字和namespace用法的描述有些困惑,即使他们试图通过查找引用来学习它,因为声明指令读起来有些等效,它们都是以d开头的相对抽象的长词。

可以通过显式命名名称空间来访问名称空间中的标识符:

myNamespace::myIdent

这可能要键入很多键。但是,如果大多数标识符以相同的方式作为前缀,这也可能降低代码的重要性。该using关键字有助于防止这些命名空间缺点。由于using是在编译器级别上工作的(它不是宏),因此其效果会持续到所使用的整个范围。这就是Google样式将其用法限制在定义明确的范围内的原因,例如,头文件中的类或cpp文件中的函数。

...当然使用声明是有区别的

using myNamespace::myIdent; // make myIdent an alias of myNamespace::myIdent

使用指令

using myNamespace; // make all identifiers of myNamespace directly accessible

如果在巨大的范围使用,后者导致很多更多的混乱。


1

干得好:

#include <iostream>

int main()
{
    std::endl(std::operator<<(std::cout, "Hello world!"));
}

通过这样编写,我们避免了使用指令和声明时容易出错的ADL。

这是一个讽刺的答案。:-D

我与Herb Sutter在Google上合作。根据C ++编码标准:

您可以并且应该在#include指令之后在实现文件中自由地使用声明和指令使用名称空间,对此感到满意。尽管反复声明相反,使用声明和指令的名称空间并不是邪恶的,它们不会破坏名称空间的目的。相反,它们是使命名空间可用的原因

您可以通过谨慎地避免使用using指令并使用声明显式指定您使用的每件事(直到运算符),来解决潜在的命名空间冲突,这些冲突可能永远不会出现,并且在这种天文学上罕见的事件中可能很难解决using,或者只是继续并开始using namespace std。我从生产率的角度推荐后者。

大多数C ++教科书都通过使用命名空间std来教初学者。他们在传播不良的编码习惯吗?

如果您问我,情况恰恰相反,我相信上面的萨特也同意。

现在,在我的职业生涯中,由于using跨数千万个LOC的代码库中的指令的直接结果,我总共遇到了大约3个命名空间冲突。但是,在所有这三种情况下,它们都位于跨越50,000行旧代码的源文件中,这些代码最初是用C编写的,然后混成C ++,执行了大量折衷的不同功能列表,包括来自十几个不同库的头文件,并且#includes跨越页面的史诗清单。尽管存在史诗般的混乱,但它们并不是很难修复,因为它们在OSX(导致代码无法构建的一个OS)上导致了构建错误,而不是运行时错误。不要以这种噩梦般的方式组织代码,您应该会很好。

就是说,避免在头文件中使用 using指令和声明。那简直是弱智。但是对于源文件,尤其是那些没有一个包含#include指令的整个页面的源文件,我想说的是,如果您不为Google工作,请不要费力。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.