我听说过使用名称空间std;这是不好的做法,我应该直接使用std::cout和std::cin。这是为什么?声明与std命名空间中的某个变量同名的变量是否有风险?
当前回答
是的,名称空间很重要。在我的项目中,我需要将一个var声明导入到源代码中,但在编译时,它与另一个第三方库冲突。
最后,我不得不用其他方法来解决这个问题,并使代码变得不那么清晰。
其他回答
一个具体的例子来澄清这个问题。假设您有两个库,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(由于该名称空间中有很多东西)。
最终,这是可写性与可靠性/可维护性之间的权衡。可读性也可能是其中的一个因素,但无论哪种方式,我都能看到这样做的理由。通常,我会说可靠性和可维护性更重要,但在这种情况下,您将不断为相当罕见的可靠性/可维护性影响支付可写性成本。“最佳”权衡将决定您的项目和优先级。
这都是关于管理复杂性的。使用名称空间会将您不想要的东西拉进来,因此可能会使调试变得更困难(我说可能)。到处使用std::很难阅读(更多的文本等等)。
马的课程-管理你的复杂性,尽你最大的能力和感觉。
我同意这里的其他观点,但我想解决有关可读性的问题——您可以通过在文件、函数或类声明的顶部使用typedef来避免所有这些问题。
我通常在类声明中使用它,因为类中的方法倾向于处理类似的数据类型(成员),typedef是一个在类上下文中分配有意义的名称的机会。这实际上有助于类方法定义的可读性。
// Header
class File
{
typedef std::vector<std::string> Lines;
Lines ReadLines();
}
在实施过程中:
// .cpp
Lines File::ReadLines()
{
Lines lines;
// Get them...
return lines;
}
而不是:
// .cpp
vector<string> File::ReadLines()
{
vector<string> lines;
// Get them...
return lines;
}
or:
// .cpp
std::vector<std::string> File::ReadLines()
{
std::vector<std::string> lines;
// Get them...
return lines;
}
为什么使用命名空间标准?
C++有一个标准库,其中包含构建应用程序时使用的常用功能,如容器、算法等。如果这些库使用的名称是公开的,例如,如果它们全局定义了一个队列类,那么您将无法再次使用相同的名称而不发生冲突。因此,他们创建了一个名称空间std来包含此更改。
不使用的原因1:不良行为
使用命名空间std的语句通常被认为是错误的做法。此语句的另一种方法是在每次声明类型时使用作用域运算符(::)指定标识符所属的命名空间。尽管该语句避免了我们在任何时候希望访问std命名空间中定义的类或类型时键入std::,但它将整个std命名空间导入到程序的当前命名空间中。
不使用的原因2:编译器变得混乱
在玩具程序中导入整个std库是可以的,但在生产级代码中,这是不好的。使用命名空间std;使命名空间std中声明的每个符号都可以在没有命名空间限定符的情况下访问。
例如:
现在,假设您升级到一个较新版本的C++,并将更多新的std命名空间符号注入到您不知道的程序中。您的程序中可能已经使用了这些符号。现在编译器将很难弄清楚声明的符号是属于您自己的实现,还是来自您在没有任何概念的情况下导入的名称空间。一些编译器会抛出错误。如果运气不好,编译器选择了错误的实现并编译它,这肯定会导致运行时崩溃。
命名空间污染影响:
虽然这种做法对于示例代码来说是可以的,但将整个std命名空间拉入全局命名空间是不好的,因为它会破坏命名空间的目的,并可能导致名称冲突。这种情况称为命名空间污染。
另一个原因是惊讶。
如果我看到cout<<blah,而不是std::cout<<blah,我会想:这是什么cout?这是正常的服装吗?有什么特别的吗?