7

我想知道 C++ 中的namespaceandusing基本上我想知道它们的区别并弄清楚如何以最好的方式使用它。

正如我所看到的,(至少)有三种方法可以解析类名,我不确定如何在其中进行选择:

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

我想知道优势,特别是如果以一种或另一种方式涉及性能,如果它只是句法和偏好问题,或者是否还有其他我没有考虑过的事情。

4

5 回答 5

6

首先是using namespace 指令,它将所有符号名称从当前命名空间中的指定命名空间带入,无论您是否需要/使用它们。当然不可取。

二是使用命名空间声明。它只会在您当前的命名空间中带来指定的符号名称。优点是您不必每次都输入完全限定的名称。

第三是符号的完全限定名称。缺点是您必须在使用符号的任何地方键入完全限定名称。

显然,第二和第三是更合适的。它们中的任何一个都没有性能差异。唯一的区别是您输入的字符数量。只需根据您的编码标准指定的内容进行选择。

编辑:
正如@Jerry 指出的那样,将声明与 ADL(参数依赖查找)结合使用可能会导致不良影响。
您可以在我的一个答案中找到详细的解释:

关于 Koenig 查找如何与命名空间一起工作以及为什么它是一件好事的详细解释?

在部分下,
为什么要批评 Koenig 算法?

于 2013-01-03T10:13:05.233 回答
4

有一种情况(诚然,有些不常见),您使用的表单确实可以产生影响,而您想要使用的表单 using namespace foo,并且它最常应用于std命名空间(即,您编写using namespace std;.

最明显的示例是您正在为用户定义的类型编写排序。这可能会应用于用户也定义了自己的类型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 库的大部分目的。

于 2013-01-03T10:29:08.753 回答
2

没有任何性能增益或损失。所有调用和变量都在编译时解析。

三者之间的选择有些主观。是的,using namespace <ns>;有时会因为污染全局命名空间而皱眉,我认为用于小文件是安全的。

我倾向于将第二个用于测试目的,我预计会发生冲突,但我会在之后将其删除。这可能会变得更加混乱,因为您最终可能会得到限定名称和非限定名称的组合:

vector<std::string> x;

因为您using std::vector;在顶部有 a,但没有using std::string;.

我更喜欢第三个。

于 2013-01-03T10:15:32.653 回答
1

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

using namespace std(或任何其他名称空间)绝对要避免在头文件中,它可以包含在任何地方,并且在其中引入符号可能会导致歧义。

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

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

主要原因是它可能导致歧义(对于编译器和人类阅读器),它还可能减慢编译本身的速度(但这并不是第一件事那么大的问题)

于 2013-01-03T10:14:27.373 回答