我听说过使用名称空间std;这是不好的做法,我应该直接使用std::cout和std::cin。这是为什么?声明与std命名空间中的某个变量同名的变量是否有风险?


当前回答

一个具体的例子来澄清这个问题。假设您有两个库,foo和bar,每个库都有自己的名称空间:

namespace foo {
    void a(float) { /* Does something */ }
}

namespace bar {
    ...
}

现在假设您在自己的程序中同时使用foo和bar,如下所示:

using namespace foo;
using namespace bar;

void main() {
    a(42);
}

现在一切都很好。当你运行程序时,它会“做一些事情”。但后来你更新了这个栏,让我们假设它变成了这样:

namespace bar {
    void a(float) { /* Does something completely different */ }
}

此时将出现编译器错误:

using namespace foo;
using namespace bar;

void main() {
    a(42);  // error: call to 'a' is ambiguous, should be foo::a(42)
}

因此,您需要进行一些维护,以澄清“a”是指foo::a。这是不可取的,但幸运的是它非常容易(只需在编译器标记为不明确的所有调用前面添加foo::)。

但想象一下另一种情况,酒吧改成了这样:

namespace bar {
    void a(int) { /* Does something completely different */ }
}

此时,您对a(42)的调用突然绑定到bar::a而不是foo::a,并且它不做“某事”,而是做“完全不同的事情”。没有编译器警告或任何内容。你的程序只是默默地开始做一些与以前完全不同的事情。

当你使用一个名称空间时,你会面临这样的风险,这就是为什么人们不喜欢使用名称空间的原因。名称空间中的东西越多,冲突的风险就越大,因此与其他名称空间相比,人们可能更不喜欢使用名称空间std(由于该名称空间中有很多东西)。

最终,这是可写性与可靠性/可维护性之间的权衡。可读性也可能是其中的一个因素,但无论哪种方式,我都能看到这样做的理由。通常,我会说可靠性和可维护性更重要,但在这种情况下,您将不断为相当罕见的可靠性/可维护性影响支付可写性成本。“最佳”权衡将决定您的项目和优先级。

其他回答

考虑

// myHeader.h
#include <sstream>
using namespace std;


// someoneElses.cpp/h
#include "myHeader.h"

class stringstream {  // Uh oh
};

请注意,这是一个简单的示例。如果您有包含20个include和其他导入的文件,那么您将有大量的依赖项来解决问题。更糟糕的是,根据冲突的定义,在其他模块中可能会出现不相关的错误。

这并不可怕,但如果不在头文件或全局名称空间中使用它,您将省去麻烦。在非常有限的范围内执行它可能是正确的,但我从未遇到过键入额外的五个字符来澄清我的函数来自何处的问题。

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

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


请注意,有些人不同意我这样说的“感觉自由”,因为尽管cpp文件中的using语句比头文件中的要好(因为它不会影响包含头文件的人),但他们认为这仍然不好(因为根据代码的不同,这可能会使类的实现更难维护)。这个C++超级FAQ条目说,

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

常见问题解答建议了两种选择:

使用声明:使用std::cout;//using声明允许您无条件使用coutcout<<“值:”;只需键入std::std::cout<<“值:”;

您需要能够阅读与您不同风格和最佳实践意见的人编写的代码。如果你只使用cout,没有人会感到困惑。但是,当你有很多名称空间到处飞的时候,你看到这个类,你不太确定它做什么时,让名称空间显式充当某种注释。您可以第一眼看到,“哦,这是一个文件系统操作”或“这是在做网络工作”。

我同意不应该在全球范围内使用它,但在本地使用它并没有那么糟糕,就像在命名空间中一样。下面是“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指令(使用名称空间Her_lib)在另一个作用域中可访问的名称。

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

经验丰富的程序员也尽量避免在源文件中使用完全限定的名称。这样做的一个次要原因是,除非有充分的理由,否则在代码较少的情况下编写更多的代码是不优雅的。一个主要原因是关闭参数依赖查找(ADL)。

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

因此,以下内容是可以的:

函数级使用指令并在函数的实现中使用声明使用源文件内声明的源文件级别(有时)使用指令的源文件级别