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


当前回答

同时使用多个命名空间显然是一个灾难,但在我看来,使用JUST命名空间std和仅使用命名空间std并不是什么大问题,因为重新定义只能由您自己的代码进行。。。

因此,只需将它们的函数视为保留名称,如“int”或“class”即可。

人们不应该对此如此吹毛求疵。你的老师一直都是对的。只需使用一个名称空间;这就是首先使用名称空间的全部意义。您不应该同时使用多个。除非它是你自己的。因此,再次定义不会发生。

其他回答

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

我同意其他人的看法——这是在要求名字冲突、歧义,但事实是它不够明确。虽然我可以看到使用的用途,但我个人倾向于限制它。我也会强烈考虑其他人所指出的:

如果你想找到一个可能是一个相当常见的名称的函数名,但你只想在std命名空间中找到它(或者反过来——你想更改所有不在命名空间std、命名空间X…中的调用),那么你打算怎么做?

你可以编写一个程序来完成它,但花时间在项目本身上而不是编写一个维护项目的程序,这不是更好吗?

就我个人而言,我其实并不介意std::前缀。我更喜欢它的外观而不是没有它。我不知道这是因为它很明确,并对我说“这不是我的代码……我正在使用标准库”,还是因为它是其他东西,但我觉得它看起来更好。这可能很奇怪,因为我最近才接触C++(使用C和其他语言的时间更长,而且C是我一直以来最喜欢的语言,就在汇编语言之上)。

还有一件事,尽管它与上述内容和其他人指出的内容有些关联。虽然这可能是不好的做法,但我有时会为标准库版本保留std::name,为特定于程序的实现保留名称。是的,这确实会咬你,咬你很厉害,但归根结底,我是从零开始这个项目的,我是唯一的程序员。例如:我重载std::string并将其称为string。我有一些有用的补充。我之所以这样做,部分原因是我的C和Unix(+Linux)倾向于小写名称。

除此之外,还可以使用命名空间别名。这里是一个可能没有提到的有用的例子。我使用C++11标准,特别是libstdc++。它没有完全的std::regex支持。当然,它可以编译,但它会抛出一个异常,这是程序员端的错误。但它缺乏实施。

下面是我解决这个问题的方法。安装Boost的正则表达式,并将其链接进来。然后,我执行以下操作,以便在libstdc++完全实现它时,我只需删除这个块,代码保持不变:

namespace std
{
    using boost::regex;
    using boost::regex_error;
    using boost::regex_replace;
    using boost::regex_search;
    using boost::regex_match;
    using boost::smatch;
    namespace regex_constants = boost::regex_constants;
}

我不会争论这是不是个坏主意。然而,我会争辩说,它为我的项目保持了干净,同时又使它变得具体:没错,我必须使用Boost,但我使用它就像libstdc++最终会使用它一样。是的,启动自己的项目并从一开始就使用标准(…)对帮助维护、开发和项目所涉及的一切都有很大的帮助!

只是想澄清一下:我实际上并不认为在STL中使用类名或其他名称来代替它是一个好主意。字符串对我来说是个例外(忽略第一个,上面的,或者这里的第二个,如果必须的话双关语),因为我不喜欢“字符串”这个概念。

事实上,我仍然非常倾向于C和C++。省略细节,我所做的很多工作更适合C(但这是一个很好的练习,也是让自己学会另一种语言的好方法)。不要对对象/类等抱有偏见,这可能更好地表述为不那么封闭、不那么傲慢、更容易接受。)。但有用的是一些人已经提出的建议:我确实使用了列表(它相当通用,不是吗?),并排序(相同的事情)以命名两个,如果我使用名称空间std;,因此,为了达到这个目的,我更喜欢具体、可控,并且知道如果我打算将其作为标准用途,那么我必须指定它。简单地说:不允许假设。

至于让Boost的正则表达式成为标准的一部分。我这样做是为了将来的集成,而且——再次,我完全承认这是偏见——我不认为它像Boost::正则表达式::。。。。事实上,这对我来说是另一回事。C++中有很多东西我还没有完全接受,包括外观和方法(另一个例子:varadic模板与var参数[尽管我承认varadic模版非常有用!])。即使那些我确实接受的人也很困难,我仍然对他们有意见。

根据我的经验,如果你有多个库使用cout,但出于不同的目的,你可能会使用错误的cout。

例如,如果我键入,使用名称空间std;并使用命名空间otherlib;如果只键入cout(恰好两者都有),而不是std::cout(或'otherlib::cout'),则可能会使用错误的一个,并出现错误。使用std::cout更有效。

考虑

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


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

class stringstream {  // Uh oh
};

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

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

为什么使用命名空间标准?

C++有一个标准库,其中包含构建应用程序时使用的常用功能,如容器、算法等。如果这些库使用的名称是公开的,例如,如果它们全局定义了一个队列类,那么您将无法再次使用相同的名称而不发生冲突。因此,他们创建了一个名称空间std来包含此更改。

不使用的原因1:不良行为

使用命名空间std的语句通常被认为是错误的做法。此语句的另一种方法是在每次声明类型时使用作用域运算符(::)指定标识符所属的命名空间。尽管该语句避免了我们在任何时候希望访问std命名空间中定义的类或类型时键入std::,但它将整个std命名空间导入到程序的当前命名空间中。

不使用的原因2:编译器变得混乱

在玩具程序中导入整个std库是可以的,但在生产级代码中,这是不好的。使用命名空间std;使命名空间std中声明的每个符号都可以在没有命名空间限定符的情况下访问。

例如:

现在,假设您升级到一个较新版本的C++,并将更多新的std命名空间符号注入到您不知道的程序中。您的程序中可能已经使用了这些符号。现在编译器将很难弄清楚声明的符号是属于您自己的实现,还是来自您在没有任何概念的情况下导入的名称空间。一些编译器会抛出错误。如果运气不好,编译器选择了错误的实现并编译它,这肯定会导致运行时崩溃。

命名空间污染影响:

虽然这种做法对于示例代码来说是可以的,但将整个std命名空间拉入全局命名空间是不好的,因为它会破坏命名空间的目的,并可能导致名称冲突。这种情况称为命名空间污染。