使用std命名空间

时间:2009-08-12 08:59:16

标签: c++ namespaces

对std命名空间使用'using'似乎有不同的看法。

有人说使用'using namespace std',其他人说不要,而是先加上与'std::'一起使用的std函数,而其他人则说使用这样的东西:

using std::string;
using std::cout;
using std::cin;
using std::endl;
using std::vector;

用于所有要使用的std函数。

各自的优点和缺点是什么?

16 个答案:

答案 0 :(得分:123)

大多数C ++用户都非常乐意阅读std::stringstd::vector等。事实上,看到原始vector让我想知道这是std::vector还是不同用户定义的vector

我总是反对使用using namespace std;。它将各种名称导入全局命名空间,并可能导致各种非明显的歧义。

以下是std命名空间中的一些常用标识符:count,sort,find,equal,reverse。拥有一个名为count的局部变量意味着using namespace std将无法使用count代替std::count

不需要的名称冲突的典型示例如下所示。想象一下,你是一个初学者,不知道std::count。想象一下,你要么在<algorithm>中使用其他东西,要么被一个看似无关的标题所吸引。

#include <algorithm>
using namespace std;

int count = 0;

int increment()
{
    return ++count; // error, identifier count is ambiguous
}

错误通常很长且不友好,因为std::count是一个带有一些长嵌套类型的模板。

这是可以的,因为std::count进入全局命名空间并且函数计数隐藏它。

#include <algorithm>
using namespace std;

int increment()
{
    static int count = 0;
    return ++count;
}

也许有点令人惊讶,这没关系。导入到声明性作用域中的标识符出现在公共名称空间中,该名称空间包含它们的定义位置和导入位置。换句话说,std::count在全局命名空间中显示为count,但仅在increment内。

#include <algorithm>

int increment()
{
    using namespace std;
    static int count = 0;
    return ++count;
}

由于类似的原因,count在这里含糊不清。 using namespace std不会导致std::count,隐藏可能出现的外部countusing namespace规则意味着std::count看起来(在increment函数中)就好像它是在全局范围内声明的那样,即与int count = 0;相同的范围,从而导致歧义。

#include <algorithm>

int count = 0;

int increment()
{
    using namespace std;
    return ++count; // error ambiguous
}

答案 1 :(得分:39)

排除基础知识(必须添加所有stl对象/函数的std :: infront,如果没有'using namespace std',则冲突的可能性更小)

值得注意的是,你永远不应该把

using namespace std

在头文件中,因为它可以传播到包含该头文件的所有文件,即使他们不想使用该命名空间。

在某些情况下,使用

之类的东西是非常有益的
using std::swap

好像有一个专门版本的swap,编译器会使用它,否则它将回退到std :: swap

如果你调用std :: swap,你总是使用基本版本,它不会调用优化版本(如果存在)。

答案 2 :(得分:25)

答案 3 :(得分:17)

永远不要在头文件中使用全局范围内的命名空间。这可能导致冲突,冲突出现的文件负责人无法控制原因。

在实施文件中,选择范围远远不够。

  • 使用using namespace std会带来该命名空间中的所有符号。这可能是麻烦的,因为几乎没有人知道那里的所有符号(因此在实践中不可能有冲突的政策)而没有说出将要添加的符号。并且C ++标准允许头部添加来自其他头部的符号(C不允许这样做)。它仍然可以在实践中很好地简化在受控情况下的书写。如果发生错误,则会在文件中检测到有问题。

  • 使用std :: name;具有写作简单的优点,没有导入未知符号的风险。成本是您必须明确导入所有想要的符号。

  • 明确排位有点杂乱,但我认为这种做法不那么麻烦。

在我的项目中,我对所有名称使用显式限定,我接受使用std :: name,我打架 反对使用命名空间std(我们有一个lisp解释器,它有自己的列表类型,因此冲突是肯定的)。

对于其他名称空间,您还必须考虑使用的命名约定。我知道一个项目使用命名空间(用于版本控制)和名称前缀。然后执行using namespace X几乎没有风险,如果不这样做会导致代码愚蠢PrefixNS::pfxMyFunction(...)

在某些情况下,您要导入符号。 std :: swap是最常见的情况:导入std :: swap然后使用swap unqualified。参数依赖查找将在类型的命名空间中找到适当的交换(如果有),如果没有则返回标准模板。


编辑:

在评论中,Michael Burr想知道冲突是否发生在现实世界中。这是一个真实的例子。我们有一种扩展语言,是一种lisp方言。我们的解释器有一个包含文件,包含

的lisp.h
typedef struct list {} list;

我们必须整合并调整一些代码(我将其命名为“引擎”),如下所示:

#include <list>
...
using std::list;
...
void foo(list const&) {}

所以我们这样修改了:

#include <list>

#include "module.h"
...
using std::list;
...
void foo(list const&) {}

好。一切正常。几个月后,“module.h”被修改为包含“list.h”。测试通过了。 “模块”没有以影响其ABI的方式进行修改,因此可以使用“引擎”库而无需重新编译其用户。集成测试没问题。新的“模块”出版。当代码没有被修改时,下一次引擎编译就破了。

答案 4 :(得分:4)

两个

using std::string;

using namespace std;

向全局命名空间添加一些符号(一个或多个)。在全局命名空间中添加符号是您应该永远在头文件中执行的操作。您无法控制谁将包含您的标头,有许多标头包含其他标头(以及包含标头的标头,包括标题等等)。

在实现(.cpp)文件中,由你决定(只记得在所有#include指令之后)。您只能破坏此特定文件中的代码,因此更容易管理并找出名称冲突的原因。如果您更喜欢在标识符之前使用std ::(或任何其他前缀,项目中可能有许多名称空间),那就没问题。如果您想将您使用的标识符添加到全局命名空间,那就没问题。如果你想把整个命名空间放在头上:-),这取决于你。虽然效果仅限于单个编译单元,但它是可以接受的。

答案 5 :(得分:3)

如果您的代码中没有名称冲突的风险,您可以使用std和其他库:

using namespace std;

但是,如果您想要准确了解代码对文档的依赖性,或者存在名称冲突的风险,请使用另一种方式:

using std::string;
using std::cout;

第三种解决方案,不要使用这些解决方案并在每次使用代码之前编写std ::为您带来更多安全性,但代码可能有点沉重......

答案 6 :(得分:3)

对我来说,我希望在可能的情况下使用::

std::list<int> iList;

我不想写:

for(std::list<int>::iterator i = iList.begin(); i != iList.end(); i++)
{
    //
}

希望用C ++ 0x我会写这个:

for(auto i = iList.begin(); i != iList.end(); i++)
{
    //
}

如果命名空间非常冗长,

namespace dir = boost::filesystem;

dir::directory_iterator file("e:/boost");
dir::directory_iterator end;

for( ; file != end; file++)
{
    if(dir::is_directory(*file))
        std::cout << *file << std::endl;
}

答案 7 :(得分:2)

您不应该在标头的命名空间范围内using namespace std。另外,我想大多数程序员都会想知道他们何时看到vectorstring没有std::,所以我认为using namespace std不是更好。因此,我认为永远不会using namespace std

如果您认为必须,请使用using std::vector之类的声明添加本地。但问问自己:这有什么价值?一行代码写入一次(可能两次),但它读取十次,一百次或一千次。保存的输入工作是添加使用声明或指令与读取代码的努力相比是边际的。

考虑到这一点,在十年前的一个项目中,我们决定使用其完整的命名空间名称明确限定所有标识符。起初看起来很尴尬的事情在两周之内成了常规。现在,在整个公司的所有项目中,没有人使用指令或声明了。 (有一个例外,见下文。)看看十年后的代码(几个MLoC),我觉得我们做出了正确的决定。

我发现通常,那些反对禁止using的人通常没有为一个项目试过它。那些尝试过的人,经常发现它比在很短的时间后使用指令/声明更好。

注意:唯一的例外是using std::swap,这是必要的(特别是在通用代码中),以获取无法放入swap()命名空间的std重载(因为我们不是'允许将std函数的重载放入此命名空间中。

答案 8 :(得分:1)

using namespace std导入当前名称空间中std名称空间的内容。因此,优点是您不必在该命名空间的所有函数前面键入std::。但是,您可能会遇到具有相同名称功能的不同命名空间。因此,你可能最终没有打电话给你想要的那个。

std中手动指定要导入的内容可以防止这种情况发生,但可能会导致在文件开头使用很长的列表,某些开发人员会觉得这很难看;)!

就个人而言,我更喜欢在每次使用函数时指定命名空间,除非命名空间太长,在这种情况下我在文件的开头使用了一些。

编辑:正如另一个答案所述,你永远不应该在头文件中加上using namespace,因为它会传播到包括这个标题的所有文件,因此可能会产生不必要的行为。

EDIT2:感谢Charles的评论,纠正了我的回答。

答案 9 :(得分:1)

命名空间保留代码以防止confusionpollution函数签名。

Hereproper namespace用法的完整文档演示:

#include <iostream>
#include <cmath>  // Uses ::log, which would be the log() here if it were not in a namespace, see https://stackoverflow.com/questions/11892976/why-is-my-log-in-the-std-namespace

// Silently overrides std::log
//double log(double d) { return 420; }

namespace uniquename {
    using namespace std;  // So we don't have to waste space on std:: when not needed.

    double log(double d) {
        return 42;
    }

    int main() {
        cout << "Our log: " << log(4.2) << endl;
        cout << "Standard log: " << std::log(4.2);
        return 0;
    }
}

// Global wrapper for our contained code.
int main() {
    return uniquename::main();
}

输出:

Our log: 42
Standard log: 1.43508

答案 10 :(得分:0)

就像在Java中你可以使用包含java.util。*或者只是单独选择每个类,它取决于样式。请注意,您不希望在文件/范围的开头有一个using namespace std,因为您将污染命名空间并可能发生冲突,从而破坏命名空间点。但是如果你有一个使用大量STL的函数,它会使代码混乱,在你的逻辑中混杂使用前缀语法,你应该考虑使用using namespace std(当使用各种类时)或个人{ {1}} s(经常使用几个课程)。

答案 11 :(得分:0)

只要您使用的IDE不够灵活,无法显示或隐藏您需要的确切信息,此讨论将继续存在。

这是因为您希望代码的外观取决于手头的任务。

在创建源代码时,我更愿意看到我正在使用哪个类:是std::string还是BuzFlox::Obs::string类?

在设计控制流时,我甚至对变量的类型不感兴趣,但我希望关注ifwhile以及continue'第

所以这是我的建议:

根据您的代码的受众和工具的强大功能,选择最简单的方式或提供大部分信息。

答案 12 :(得分:0)

有几种方法可以解决这个问题。

首先:像你所做的一样使用。

第二:做namespace S = std;,减少2个字符。

第三:使用static

第四:不要使用std使用的名称。

答案 13 :(得分:0)

除了这里的许多正确答案外,我想陈述一个经常被遗忘的细节:由于常见的编码和链接方案,许多开发人员似乎误解了C ++中的翻译单元的概念。对于我们大多数人来说,这很常见,.h文件是头文件,.cpp文件会产生实现细节,但这只是一个共识,而不是严格的标准规则。您最终如何决定翻译单位的选择取决于您。

因此,例如使用UnityBuilds(将所有内容链接到一个翻译单元以提高速度和存储目的),您就不再可以依靠普遍同意,在.cpp文件中使用名称空间通常是可以的。有人可能会争辩说,UnityBuilds绕过了几种主要的C ++核心哲学,因此它们本身就是一个主题,但是尽管如此,在其他情况下仍可能出现类似的问题(例如,函数中包含本地)。顺便提一句,匿名名称空间的使用也会出现类似的问题。

由于过去这一直是我的问题,因此我想出了“内部准则”,以便在比例允许的情况下尽可能明确。

答案 14 :(得分:-1)

  

每个

的优点和缺点是什么?

离开std ::的唯一理由是,理论上你可以自己重新实现所有的STL功能。然后你的函数可以从使用std :: vector切换到my :: vector而不需要改变代码。

答案 15 :(得分:-1)

为什么不例如

typedef std::vector<int> ints_t;
ints_t ints1;
....
ints_t ints2;

而不是笨拙的

std::vector<int> ints1;
...
std::vector<int> ints2;

我发现它更具可读性,也是我编码的标准。

您甚至可以使用它为读者包含一些语义信息。例如,考虑函数原型

void getHistorgram(std::vector<unsigned int>&, std::vector<unsigned int>&);

哪些是返回值?

如何改为

typedef std::vector<unsigned int> values_t;
typedef std::vector<unsigned int> histogram_t;
...
void getHistogram(values_t&, histogram_t&);