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


当前回答

这里有一个我在其他答案中都没有找到的观点:只使用一个名称空间。根据大多数答案,命名空间不好的主要原因是,你可能会有冲突的函数名,这会导致一片混乱。但是,如果只使用一个名称空间,则不会发生这种情况。确定您将使用最多的库(可能使用名称空间std;)并坚持使用它。

可以认为它有一个不可见的库前缀-std::vector变成了vector。在我看来,这是两全其美的:一方面,它减少了必须进行的键入(正如名称空间所预期的那样),另一方面,为了清晰和安全,它仍然需要使用前缀。如果有一个函数或对象没有名称空间前缀,那么您知道它来自您声明的一个名称空间。

请记住,如果您决定在全球范围内使用一个,请不要在本地使用其他。这又回到了其他答案,即本地名称空间通常比全局名称空间更有用,因为它们提供了各种便利。

其他回答

考虑两个名为Foo和Bar的库:

using namespace foo;
using namespace bar;

一切都很好,你可以从Foo调用Blah(),从Bar调用Qux()。但有一天你升级到了Foo 2.0的新版本,它现在提供了一个名为Qux()的函数。现在出现了一个冲突:Foo 2.0和Bar都将Qux()导入到全局命名空间中。这将需要一些努力来解决,特别是如果函数参数恰好匹配。

如果您使用了foo::Blah()和bar::Qux(),那么引入foo::Qux()将是一个非事件。

我也认为这是一种糟糕的做法。为什么?就在一天,我认为名称空间的功能是划分内容,所以我不应该将所有内容都放在一个全局包中而破坏它。

然而,如果我经常使用“cout”和“cin”,我会写:使用std::cout;使用std::cin;在.cpp文件中(当它使用include传播时,不会在头文件中)。我想,没有一个理智的人会说出一条小溪的名字

一个具体的例子来澄清这个问题。假设您有两个库,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(由于该名称空间中有很多东西)。

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

#include <iostream>

using namespace std;

int main() {
  // There used to be
  // int left, right;
  // But not anymore

  if (left != right)
    std::cout << "Excuse me, WHAT?!\n";
}

那么,为什么?因为它引入了与常用变量名重叠的标识符,并允许编译此代码,将其解释为if(std::left!=std::right)。

PVS Studio可以使用V1058诊断程序找到这样的错误:https://godbolt.org/z/YZTwhp(谢谢Andrey Karpov!!)。

Ping cppcheck开发人员:您可能希望标记此项。这是一场灾难。

它不会使您的软件或项目性能更差。在源代码开头包含名称空间还不错。using namespace std指令的包含根据您的需求以及开发软件或项目的方式而有所不同。

命名空间std包含C++标准函数和变量。当您经常使用C++标准函数时,这个名称空间非常有用。

如本页所述:使用命名空间std的语句通常被认为是错误的实践此语句的替代方法是指定使用作用域运算符(::)将标识符所属的命名空间每次我们声明一个类型。请参阅以下意见:在源文件中使用“using namespace std”没有问题当您大量使用命名空间并确信任何东西都不会碰撞。

有些人曾说过,在源文件中包含using命名空间std是一种不好的做法,因为您正在从该命名空间调用所有函数和变量。当您想定义一个与命名空间std中包含的另一个函数同名的新函数时,您会重载该函数,因为编译或执行可能会产生问题。它不会像您期望的那样编译或执行。

如本页所述:尽管该语句使我们不必在任何时候输入std::我们希望访问std命名空间中定义的类或类型将整个std命名空间导入当前命名空间该计划的一部分。让我们举几个例子来理解为什么可能不是什么好事...现在,在开发的后期阶段,我们希望使用cout是在某个名为“foo”的库中自定义实现的(用于示例)...注意这里有一个歧义,cout指向哪个库?编译器可能会检测到这一点,而不会编译程序。在最坏的情况下在这种情况下,程序仍可能编译,但调用了错误的函数,因为我们从未指定标识符属于哪个命名空间。