我听说过使用名称空间std;这是不好的做法,我应该直接使用std::cout和std::cin。这是为什么?声明与std命名空间中的某个变量同名的变量是否有风险?
当前回答
这是一种糟糕的做法,通常被称为全局命名空间污染。当多个名称空间具有相同的函数名和签名时,可能会出现问题,那么编译器决定调用哪个名称空间是不明确的,当您使用std::cout这样的函数调用指定名称空间时,这一切都可以避免。希望这有帮助。:)
其他回答
一个具体的例子来澄清这个问题。假设您有两个库,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(由于该名称空间中有很多东西)。
最终,这是可写性与可靠性/可维护性之间的权衡。可读性也可能是其中的一个因素,但无论哪种方式,我都能看到这样做的理由。通常,我会说可靠性和可维护性更重要,但在这种情况下,您将不断为相当罕见的可靠性/可维护性影响支付可写性成本。“最佳”权衡将决定您的项目和优先级。
命名空间是为了避免命名冲突。C++基于C,C在函数和变量名方面有很多问题,因为有时来自不同库的函数会发生冲突。因此,库开发人员开始在其函数前面加上库名,如下所示:
foo/foo.h:
void libfoo_foo_foo_h_open(); // the name can be weird then even this one!
C++引入了名称空间,以一种简单的方式解决了这个问题。
假设您有两个名为file和window的库,分别处理文件和窗口,代码如下:
#include <file.h>
#include <window.h>
using namespace file;
using namespace window;
void open() {
...
}
文件.h:
namespace file {
void open(); // What!
}
window.h:
namespace window {
void open(); // Oh no!
}
上面的代码肯定无法编译。
如果你不喜欢键入std::(只有5个字符),你可以一直这样做:(在头文件中不是个好主意)
using s = std;
如果您仍然想使用名称空间std;在您的源文件中,那么您正在引发这个问题,我必须问您“NAMESPACE的目的是什么?”。
对于不合格的导入标识符,您需要像grep这样的外部搜索工具来查找标识符的声明位置。这使得关于程序正确性的推理更加困难。
这是一种糟糕的做法,通常被称为全局命名空间污染。当多个名称空间具有相同的函数名和签名时,可能会出现问题,那么编译器决定调用哪个名称空间是不明确的,当您使用std::cout这样的函数调用指定名称空间时,这一切都可以避免。希望这有帮助。:)
不要全局使用它
只有在全球范围内使用时,它才被认为是“坏的”。因为:
你把正在编程的命名空间弄得乱七八糟。当您使用许多名称空间xyz;时,读者将很难看到特定标识符的来源;。无论对你的源代码的其他读者来说是什么,对最经常阅读源代码的读者来说更是如此:你自己。一两年后回来看看。。。如果您只讨论使用名称空间std;你可能不知道你抓取的所有内容——当你添加另一个#include或移动到一个新的C++修订版时,你可能会遇到你不知道的名称冲突。
您可以在本地使用
继续,在本地(几乎)自由使用它。当然,这可以防止你重复std::--,重复也是不好的。
本地使用它的习惯用法
在C++03中,有一种习惯用法——样板代码——用于为类实现交换函数。有人建议您实际使用本地using命名空间std;--或至少使用std::swap;:
class Thing {
int value_;
Child child_;
public:
// ...
friend void swap(Thing &a, Thing &b);
};
void swap(Thing &a, Thing &b) {
using namespace std; // make `std::swap` available
// swap all members
swap(a.value_, b.value_); // `std::stwap(int, int)`
swap(a.child_, b.child_); // `swap(Child&,Child&)` or `std::swap(...)`
}
这有以下魔力:
编译器将为value_选择std::swap,即void std::swap(int,int)。如果实现了重载void swap(Child&,Child&),编译器将选择它。如果没有重载,编译器将使用void std::swap(Child&,Child&),并尽可能地交换这些。
对于C++11,没有理由再使用这种模式了。对std::swap的实现进行了更改,以找到一个潜在的过载并选择它。