使用"std"的标准惯例

11

5
不要使用第二种约定,否则你会失去理智。 - Hassan Syed
7
当然,第二种惯例是正确的。 - anon
1
根据上下文,第二个或第三个。第一个仅用于“Hello World”教程或快速演示。 - Martin York
另请参见https://dev59.com/H3VC5IYBdhLWcg3wrDRd - Assaf Lavie
请参考以下链接:https://dev59.com/gXM_5IYBdhLWcg3wslfs - missingfaktor
9个回答

14

这里提供了一个很好的解释,可以在这里找到。

第一种风格即使用命名空间“using namespace whatever”的做法完全打败了使用命名空间的初衷。除了在小代码片段中,你永远不应该使用它。(我甚至在那里也不用!:D)

第二种方法过于冗长。不切实际。

我个人喜欢第三种风格,即输入完整的名称(例如std::cout)。

请记住,代码被读取的次数比被编写的次数多得多,使用完全限定名称会使你的代码更易读。


6
编程中任何概念的目的都是让程序员的生活更加轻松。如果你经常使用标准库,使用using可以让你的代码更加简明扼要。相比于std::string a; std::string b; std::string c; std::string d;using std::string; string a; string b; string c; string d如何更冗长呢?如果你需要经常使用它,完全限定的名称会让人感到繁琐。而且,当已经有了std::string时,谁还会手写自己的string类呢?如果你说string x,95%的情况下是指std::string,而且每个人都知道。 - Chris Lutz
这是一个例外。如果您说“使用std :: count”,然后稍后需要定义具有相同名称的函数或变量,该怎么办? - missingfaktor
6
不同意:我不认为在源文件中使用using namespace std;会有任何问题。但是绝对不要在头文件中使用#1或#2。 - rlbond
1
@rlbond: 我的观点是,无论使用哪种风格,都应该保持一致。这就是为什么我总是坚持第三种风格。适用于标头和源文件。而正如你所看到的,这一切都归结为风格问题。并不是所有人都适合同一种风格! - missingfaktor
8
这是来自我原始帖子中发布的 Marshall Cline 链接的内容: “我个人发现键入“std::”比为每个不同的std名称决定是否包含using声明以及在哪里添加它的最佳作用域更快。” - missingfaktor
在我看来,第一种风格绝不会违背命名空间的目的。如果由于命名空间冲突而存在歧义,可以通过指定来解决。代码的可读性至关重要,第一种风格确实可以提高可读性。 - MattyT

12

这个问题之前已经被问过很多次了,但是我的SO搜索技能似乎暂时失灵了。基本上:

  • 永远不要在头文件中放置任何类型的using指令 - 这样做会污染您的代码并引入各种难以跟踪的错误。

  • 最好在实现(.cpp)文件中使用类似using std::string的using声明,如果该类型被广泛使用。

  • 作为最后的选择,在实现文件中使用using namespace std,但只限于实现文件 - 我在SO上发布可编译代码时使用它,以方便大家。


对于小型实现文件,我认为使用命名空间没有问题。我想如果你有一个巨大的类,可能会遇到问题。 - Steve
2
什么是“小”?我不写庞大的类,但也不会把C++标准库中的每个名称都记在脑子里。明确指定我常用的名称可以避免讨厌的(而且非常难以调试的)问题。 - anon
虽然ADL可以解决您避免在上下文中污染标准函数名称的最佳计划,但是如果您打算将名称“copy”用于其他内容,则最好确保您永远不会意外调用您的版本,而是调用ADL找到的重载,反之亦然。#include <vector> #include <algorithm> int main() { std::vector<int> foo; std::vector<int> bar; copy(foo.begin(), foo.end(), bar.begin()); } - Steve Jessop
1
我想强调一下,using(指令/语句)是可以有范围的。所以尽量在使用它时要具体明确。 - Martin York
@Martin York:但是,Visual Studio 2008似乎处理不正确,会使任何using指令文件作用域。 - rlbond
@rlbond:太可怕了!他们有没有修复这个缺陷的计划?将“using”指令的范围提升可能会带来灾难性后果。 - D.Shawley

8
这是我在同一主题上撰写的另一个答案的修改版。如果有足够多的这些问题,也许我最终会得出一个明确的帖子 ;)
主要问题是名称冲突,如果你的代码中有一个名为cout的变量,并且你正在使用namespace std;,那么它将不明确你的意思。这不仅仅是cout。count、reverse和equal也将被包括在内,这些都是常见标识符。
忽略编译器的所有问题,这也是阅读你的代码的其他人的问题。这5个额外字符确保下一个维护你代码的人准确知道你的意思。
值得注意的是,你永远不应该放置
using namespace std;

在头文件中,命名空间会传播到包含该头文件的所有文件中,即使它们不想使用该命名空间。另一个问题是不清楚是否已导入std命名空间,因此维护人员(或者三个月后的你)添加了与某些模糊的std函数同名的变量,这个函数被编译成同一单元,然后花费一个小时来查找编译错误的原因。
在大多数情况下,使用像...这样的东西非常有益。
using std::swap

如果有一个专门的版本的swap,编译器将使用它,否则它将退回到std::swap。如果您调用std::swap,则始终使用基本版本,即使存在专门的版本也不会调用它。
例如,考虑使用pimpl习语的代码。默认情况下,复制可能会复制实际实现中的所有数据,而实际上只需要交换指针。使用专门的swap可以节省大量执行时间,并且设计良好的库应该对其进行专门化。
总之,
- 始终优先使用using std::swap而不是std::swap()。 - 尽量避免在头文件中使用using namespace std,因为它会传播,尝试避免在实现文件中使用它。 - 在每个文件的顶部有数千个using std::foo不是正确的方法。最多使用它来常用类。
其他一切都是观点。

+1:有趣的关于std::swap使用的想法,我个人不太同意。然而,在阅读了2000年的USENET帖子(http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/b396fedad7dcdc81)后,我对它更感兴趣了。个人而言,我更倾向于“使用`std::swap`并进行特化”的阵营。 - D.Shawley

3
我个人更喜欢第三个选项。只要看看这个就行了:
namespace A { int a=0; }
namespace B { int a=0; }

你可以将其用作:

using namespace A;
using namespace B;
using namespace std;

cout<<a<<endl; //error here!

如果您可以简单地说:

std::cout<<B::a<<std::endl; //No problem, more readable

虽然打代码需要更多的时间,但第二和第三个选项更受欢迎。


3
如果您在符号周围不加空格,那么这些内容的易读性不会更高或更低。 在 Stack Overflow 上的代码片段仍然可以看起来不错。 - Chris Lutz

1
这是一个风格问题,但有一件事情需要注意:你永远不应该将命名空间引入到全局作用域中。例如:
#include <iostream>
using namespace std; // Pollution!

int main()
{
    ....
}

如果你想要导入命名空间,只需将其导入到你正在工作的范围即可:

#include <iostream>

int main()
{
    using namespace std; // Good!
    ....
}

不一定。这取决于您的程序(大小、使用标准库的程度等)。 - Brian Neal
2
@Brian 你的意思是将一个命名空间导入到全局作用域中是可以的吗?! - Khaled Alshaya
1
我会说这是可以的。虽然不在头文件中,但没关系。对于这些事情抱有教条主义态度是不好的,在大多数情况下也不是可怕的。例如,如果我要在源文件中使用图形库,那么说using namespace MyGraphLibrary;就可以了。世界不会爆炸,你的代码也没问题。只要小心,它就不会污染代码。 - rlbond
@AraK不应该出现在头文件中,但在源文件中,在正确的情况下是完全可以接受的。 - Brian Neal

1

我想指出的是,using namespace foo 是有作用域的。例如:

#include <iostream>
#include <vector>
//...
for (int i=0; i<10; ++i)
{
    using namespace std;
    cout << i << endl;
}
vector v; // won't compile

当小心使用时,using namespace std 可以同时有用和无害。


1

我总是列出完整的命名空间。这样可以提高可读性,让其他人知道你的函数和数据来自哪里。当阅读其他人的代码时,using非常烦人,特别是当我想要学习某些东西时,因为我无法确定它是该命名空间的一部分还是另一个命名空间的。就像这些明智的人所说的那样,它确实违背了命名空间的初衷,不是吗?重点是保持每个部分的独立性并赋予数据和逻辑含义。

一个好的顺序要记住:最重要的人是使用程序的客户端;第二重要的是维护或试图从你的代码中学习的其他程序员;最不重要的是你自己。 :-)


0

当命名空间是std时,推荐写出完全限定名称,其中std::只增加了5个额外字符。但当命名空间堆叠时,你面临着编写以下类似代码的问题:

if (NumberOfInstances > 0 && (code_type == MyNamespace::MyLongButMeaningfulClassName::EnumDefinedWithinClass::CODE_GREEN ||
                              code_type == MyNamespace::MyLongButMeaningfulClassName::EnumDefinedWithinClass::CODE_YELLOW)) {

尤其是当你的公司有一份将行数限制在80个字符以内的样式指南,并且你还添加了一些额外的缩进时,这样的代码会掩盖住所有冗长词句背后的逻辑。到了那个时候,你就会开始欣赏起使用和/或局部命名空间别名来提高可读性了。

-4

随你喜欢。实际上,这并不重要。 然而,大多数代码片段使用

using namespace std;

2
这样做完全违背了命名空间的初衷。 - missingfaktor
3
这是因为大多数代码片段都很小,旨在最大限度地提高可读性。生产代码首先是为了最大程度的健壮性而设计的,其次才是可读性。引入整个命名空间会使编写的代码变得脆弱,特别是如果你将其放在头文件中。 - Steve

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接