2013-01-03 104 views
6

我想知道一点关于在C namespaceusing ++基本上我想知道的差异,并找出如何以最好的方式使用它。C++名称解析

当我看到它有(至少)三种方式来解决一类的名字,我不知道如何选择其中:

  1. using namespace <namespace>
  2. using <namespace>::<what_to_use>
  3. <namespace>::<what_to_use> <use_it>

我想知道的优点,特别是如果有涉及一个或其他方式表现,如果它只是句法和我偏好东北黑钙土或者有其他的事情我还没有这方面考虑。

+1

它与运行时性能无关。 –

+1

我在大学时被告知,除了范围内的所有名称空间外,使用'using namespace std;'也是一个安全隐患。 –

+1

1.因为你描述的原因而气馁2.帮助你在ADL的帮助下使用他人提供的函数(参见'std :: swap',尽管让答案更好地向你解释这一点)3。我最喜欢的,但这是一个味道的问题,如果你不喜欢在所有地方看到“std ::”,那么可能会很麻烦。但他们都没有任何性能差异,它们只是名称解析,并没有*“编译成实际的代码”*。 –

回答

5

首先是using namespace directive,它汇集了来自于当前的命名空间指定的命名空间的所有符号名称,不论你是否需要/使用它们。当然是不可取的。

二是using namespace declaration。它只会在您当前的命名空间中引入指定的符号名称。好处是,你不必键入完全合格的名称每次。

三是标准名称的符号。缺点是,你必须到处都用符号输入完全合格的名称。

显然,二&三是比较适合的。它们之间没有性能差异。唯一的区别是你输入的字符数量。简单地说,根据你的编码标准的具体情况来选择。

编辑:
作为@Jerry所指出的,在与ADL(参数依赖查找)组合使用声明可以导致不期望的效果。
你可以找到自己的答案一个一个详细的解释:

Detailed explanation on how Koenig lookup works with namespaces and why its a good thing?

下的部分,
为什么柯尼希算法的批评?

+0

我很喜欢*使用名称空间声明*,因为我可以把它放在我的.cpp文件中,而且我有一个列表,我在其中看到“这是从这个文件中的这些名称空间使用的”,但我也有*完全限定名字*,因为他们告诉我,只要我看到他们说这个功能来自这个名字空间。但是,好吧,我想我是在做某种混合的事情,并且从我得到的答案中我感到安全。感谢您花时间解释这一点。 – qrikko

+1

@qrikko:通常会按组织的编码标准进行。否则,这是个人选择。重要的是一旦你做出选择,就要保持一致。 –

+0

@qrikko:不幸的是,如果你通读了我的答案,你会意识到1)你不像你想象的那么安全,2)所有声称不会对性能产生任何影响的答案是(间接的)至少可能是错误的。他们是正确的,你指定名称的形式并不直接影响绩效,但仍然错误地表示(甚至暗示)绩效不会受到影响。 –

0

主要的原因是,它可能会导致歧义(包括编译器和人类阅读器),它也可以放缓编译本身(但是这不是大问题,因为第一件事)

2

有没有性能无论如何获得或惩罚。所有调用和变量都在编译时解析。

三者之间的选择有点主观。是的,using namespace <ns>;有时被污染的全球命名空间,,但我认为它是安全的使用小文件。

我倾向于使用第二个用于测试目的的地方,但我期望发生冲突,但之后我会将其删除。这可以让混乱,因为你可以用两个合格和未合格名的组合结束了:

vector<std::string> x; 

因为你有一个using std::vector;在顶部,而不是using std::string;

我是第三位。

1

对代码的性能没有影响,这纯粹是编译时的事情。它可能(理论上)对编译时间有一些影响,但我怀疑它会达到可测量的比例。

using namespace std(或任何其他名称空间)肯定要避免在头文件中,头文件可以包含在任何地方,并在其中引入符号可能会导致含糊不清。

通常,名称空间的存在是为了避免名称冲突,并且using namespace破坏了这一目的。 using the_namespace::some_id也是如此,程度较低。有没有明确的回答你的问题,但我一般遵循以下规则:

  1. 决不using namespace在头文件。
  2. 避免using namespaceusing,除非它可以节省大量的打字。如有必要,使用名称空间别名(即,namespace abbrv = some_really::long_and::nested_namespace;)。
  3. 尝试限制using的范围:您可以将其放入函数和块以及命名空间范围。也就是说,如果您的.cpp文件中有日志记录功能,请将using std::cout;using std::endl;(或您正在使用的任何内容)放入函数体中,而不是放入文件范围。
4

有一个(当然,有些少见)情况,即你使用真正的形式可以有所作为,而且要使用形式为using namespace foo,它的最普遍应用于std命名空间(也就是说,你写using namespace std;

最明显的例子是,你写一个排序的用户定义类型,它是可能,这将被应用到该用户还定义了一个类型的拥有swap

如果用户想要使用swap,如果他们已经定义了swap,就会陷入困境,但如果他们没有定义,则使用std :: swap。如果您在代码中直接使用std::swap,那么即使类型具有自己定义的交换,您也将最终使用std::swap。相反,如果您直接为该类型指定一个交换,并且没有提供交换,则代码将无法编译。

要解决这个问题,你做这样的事情:

using namespace std; 

template <class Iter> 
void my_sort(Iter first, Iter last) { 
    // ... 
    if (*last < *first) 
     swap(*first, *last); 
} 

这将找到交换专门针对类型进行比较(即,在同一个命名空间作为类型定义的swap),如果有一个(通过依赖于参数的查找)和std::swap(如果没有为该类型定义)(通过using namespace std;)。

这可能会对性能产生影响 - 如果他们专门为它们的类型编写了交换,那么通常可以预期这是因为通过这样做,它们可以提供更好的性能。这意味着明确指定std::swap可能会起作用,但可能会导致性能下降。 (除了上面的情况,我在写代码的时候),我更喜欢给出全名(例如,std::swap)至少有两种可能性可能是首选,我想给编译器足够的余地来选择正确的。

另一次我发现使用有用的声明/指令时,命名空间得到真正深层嵌套。 Boost(对于一个明显的例子)有一些名称,如果您每次使用完全限定的名称,那么这些名称会太方便使用。对于(现在感谢,主要是过时的)Boost Lambda库来说尤其如此,在这里你使用了像_1这样的占位符,它最终会像boost::lambda::placeholders::_1一样(但是我要从内存中去掉,所以这可能至少部分是错误的)如果你坚持使用完全合格的名字。这将首先破坏使用lambda库的大部分目的。

+0

我相信这里增加了一些有价值的信息。要考虑的事情,因为它实际上**做**在这些情况下选择哪一个。感谢您提出。 – qrikko

+2

然而,我会说,在这种情况下,你更愿意使用'使用std :: swap;' –