using namespace std
',而其他人则说使用这样的东西:using std::string;
using std::cout;
using std::cin;
using std::endl;
using std::vector;
用于所有将要使用的std函数。
有什么优点?的利弊?
#1 楼
大多数C ++用户都很高兴阅读std::string
,std::vector
等。实际上,看到原始的vector
让我怀疑这是std::vector
还是其他用户定义的vector
。我始终反对使用
using namespace std;
。它将各种名称导入到全局名称空间中,并且可能引起各种非显而易见的歧义。以下是
std
名称空间中的一些常见标识符:计数,排序,查找,相等,反向。拥有名为count
的局部变量意味着using namespace std
将使您无法使用count
而不是std::count
。不想要的名称冲突的经典示例如下所示。想象一下您是一个初学者,对
std::count
一无所知。假设您正在<algorithm>
中使用其他功能,或者它被看似无关的标头拉入。带有一些长嵌套的类型。没关系,因为
std::count
进入了全局名称空间,而函数计数将其隐藏了。也许有些令人惊讶,这还可以。导入到声明性作用域中的标识符出现在公共命名空间中,该命名空间同时包含了定义它们的位置和导入它们的位置。换句话说,std::count
在全局命名空间中显示为std::count
,但仅在count
内部可见。#include <algorithm>
using namespace std;
int count = 0;
int increment()
{
return ++count; // error, identifier count is ambiguous
}
并且出于类似的原因,
increment
在这里是不明确的。 count
不会引起using namespace std
,请隐藏外部std::count
。 count
规则意味着using namespace
看起来(在std::count
函数中)看起来像是在全局范围内声明的,即在与increment
相同的范围内声明,因此引起了歧义。评论
但是如果没有std ::前缀,它的键入非常容易!
–xtofl
09年8月12日在9:57
@xtofl:不,不是。键入时五个字符无关紧要,但是阅读时这五个字符可能非常相关。易于阅读比源代码易于键入更为重要,因为代码的可读性比编写的要多。
–sbi
09年8月12日10:00
您可以添加using语句与范围规则一起正确运行。
–马丁·约克
09年8月12日在14:40
@Martin York:更新了带有示例作用域规则的示例。 @Michael Burr:可以说这还算不错,我真正不喜欢的是简单错误的错误信息很难解释,或者根本不发生。例如,如果一个函数被认为在范围之内,但不是,而std ::函数在,而不是得到一个有用的“识别器未识别”错误,那么您通常会遇到一个更加晦涩的“无法转换参数” X”或“无法从模板生成函数”样式错误。更糟糕的是,如果错误地调用了一个错误的函数。很少见,但确实如此。
– CB Bailey
09年8月12日在21:47
好吧,很惊讶没有人讨论使用std :: xxx;的选项。它不会造成名称空间污染,编写代码会更短,而且我认为copy的可读性比std :: copy大得多。
–legends2k
2010-2-18在23:43
#2 楼
不包括基础知识(必须在所有stl对象/函数之前添加std ::,如果没有“使用命名空间std”,则冲突的可能性较小)还值得注意的是,您应该永远不要将
using namespace std
放置在头文件中,因为即使它们不想使用该名称空间,它也可以传播到包含该头文件的所有文件。 br />
在某些情况下,使用诸如
using std::swap
很有好处,就像有特殊版本的swap一样,编译器会使用,否则它将退回到
std::swap
。如果调用
std::swap
,则始终使用基本版本,而不会调用优化版本(如果存在)。评论
使用std :: swap(这是我唯一使用过的东西)来提及+1。
–sbi
09年8月12日在9:47
+1表示u n可以传播。只是要注意,它也可能会侵入正确构造的标头中:它们只必须包含在流氓标头之后。
– Qumrana
09年9月5日在17:09
但是,如果要定义交换或移动(或哈希,较少等)专业化,则无论如何都应将该专业化放入命名空间std中。例如:名称空间std {template <>类hash
– AJMansfield
2015年11月30日17:30
#3 楼
首先,使用一些术语:使用声明:
using std::vector;
使用指令:
using namespace std;
我认为使用using指令很好,只要在头文件的全局作用域中不使用它们即可。因此,在.cpp文件中包含
using namespace std;
并不是一个真正的问题,而且事实证明,它完全在您的控制之下(甚至可能是如果需要,则适用于特定的块)。我看不出有什么特别的理由来用大量的
std::
限定词来弄乱代码-它只是一堆视觉噪声。但是,如果您没有在代码中使用来自std
命名空间的全部名称,那么我也看不到省略该指令的问题。这是一种重言式-如果该指令不是必需的,则无需使用它。 同样,如果您可以在
std
命名空间中使用一些用于特定类型的using-声明(而不是using-directives),那么就没有理由不应该只带那些特殊的名称到当前名称空间中。出于同样的原因,我认为这很疯狂,而且当单个using指令也能达到目的时,簿记会麻烦有25或30个use-声明。请记住,有时必须使用using声明。请参阅《有效C ++,第三版》中的Scott Meyers的“第25项:考虑对非抛出交换的支持”。为了使通用的模板化函数对参数化类型使用“最佳”交换方法,您需要使用使用声明和参数相关的查找(又名ADL或Koenig查找):
template< typename T >
void foo( T& x, T& y)
{
using std::swap; // makes std::swap available in this function
// do stuff...
swap( x, y); // will use a T-specific swap() if it exists,
// otherwise will use std::swap<T>()
// ...
}
我认为我们应该看看大量使用命名空间的各种语言的通用用法。例如,Java和C#在很大程度上使用名称空间(可以说比C ++更大)。在这些语言中,名称空间中最常见的名称使用方式是将它们与使用指令等效,从而将它们带入当前范围。这不会引起广泛的问题,而且很少会通过完全限定的名称或通过别名处理有问题的名称,以“例外”的方式处理问题,就像在C ++中一样。
Herb Sutter和Andrei Alexandrescu在他们的书《 C ++编码标准:101规则,准则》的“项目59:不要在头文件中或#include之前写名称空间使用情况”中说和最佳做法:
简而言之:您可以并且应该在
#include
指令之后在实现文件中自由地使用声明和指令使用命名空间,并对此感到满意。尽管反复声明相反,使用声明和指令的名称空间并不是邪恶的,它们不会破坏名称空间的目的。相反,它们是使命名空间可用的原因。在“ C ++编程语言,第三版”中经常引用Stroupstrup说:“不要污染全局命名空间”。实际上,他确实说过(C.14 [15]),但在参考C.10.1章时,他说: >本地范围。 using指令不会
;它只是使名称
在声明它们的范围内可访问。例如:
namespaceX {
int i , j , k ;
}
int k ;
void f1()
{
int i = 0 ;
using namespaceX ; // make names from X accessible
i++; // local i
j++; // X::j
k++; // error: X::k or global k ?
::k ++; // the global k
X::k ++; // X’s k
}
void f2()
{
int i = 0 ;
using X::i ; // error: i declared twice in f2()
using X::j ;
using X::k ; // hides global k
i++;
j++; // X::j
k++; // X::k
}
本地声明的名称(通过普通声明声明或使用using声明声明
)隐藏了非本地
具有相同名称的声明,以及任何
名称的非法重载
,在声明时被检测到。
请注意
中
k++
的歧义错误f1()
。没有赋予全局名称优先于在全局范围内可访问的名称空间中的名称
。
这提供了重要的保护
,防止意外的名称冲突,并且–
重要的是–确保
污染全局名称空间不会带来任何好处。
当声明许多名称的库
通过
使用-指令,这是一个显着的优点
,未使用的名称冲突不会被视为错误。
...
我希望看到一个基本的与传统的C和C ++程序相比,在使用命名空间的新
程序中减少了全局名称的使用。
命名空间的规则是专门设计的,
不会使
懒惰的全局名称用户优于那些不污染的人。全局范围。
又如何与“全局名称的懒用户”具有相同的优势?通过利用using伪指令,可以安全地使名称空间中的名称可用于当前作用域。 using指令(通过将指令放置在
std
之后)不会污染全局名称空间。只是使这些名称易于使用,并提供持续的冲突保护。评论
关于您的最后一点:Java和C#也具有更整洁的名称空间。如果BCL中的所有内容都驻留在System中,则“使用System”将引起与“使用命名空间std”一样多的麻烦。
–杰夫·哈迪(Jeff Hardy)
09年8月12日在16:58
但是,我看到的Java和C#程序通常会引入它们使用的所有名称空间-而不仅仅是“系统”(或其等效名称)。因此,有5个或10个执行或多或少的相同功能,而不是引入所有已使用名称的单个using指令。另外,是否“使用名称空间标准”;真的造成那么多麻烦吗?
– Michael Burr
09年8月12日在17:31
问题在于std的通用名称过多,而包含一个标准头的标准名称可能包括所有其他名称。我们对进口的商品没有很好的控制,存在太多的风险。我对Java和C#的了解还不够,但是我对Ada的了解却比C ++更好,并且模块输入系统通常不受欢迎。通常,首先是命名约定(我见过人们使用前缀和名称空间,不导入没有意义),然后才是样式。
– AProgrammer
09年8月12日在17:38
我仍然不相信这是一个现实问题。我看到使用指令一直使用,没有严重的缺点。再说一次,不使用它们我没有问题。我只是更喜欢std ::限定词而不会使代码混乱—还有其他方法可以避免这种情况(使用声明或typedef通常可以解决问题)。
– Michael Burr
09年8月12日在18:03
@AProgrammer:您说的是,“ list是用于在lisp解释器中标识列表的自然标识符”-但具有“使用命名空间std”;指令不会阻止您声明自然标识符'list'-只是如果您这样做,就不能再使用std :: list而不对其进行限定。这与没有“使用命名空间标准”的情况没有什么不同。指示。还是我错过了什么?
– Michael Burr
09年8月12日在20:22
#4 楼
切勿在头文件的全局范围内使用命名空间。这可能会导致冲突,并且出现冲突的文件负责人无法控制原因。在实现文件中,选择的内容要少得多。 />
放置使用名称空间std会带来该名称空间中的所有符号。这可能很麻烦,因为几乎没有人知道其中所有的符号(因此,在实践中不可能应用无冲突的策略),而不必说要添加的符号。 C ++标准允许标头添加其他标头中的符号(C语言不允许这样做)。在实践中,仍然可以很好地简化受控案例中的编写。并且如果发生错误,则在有问题的文件中检测到该错误。
使用std :: name;具有编写简单的优点,而没有导入未知符号的风险。代价是必须显式地导入所有想要的符号。
在我的项目中,我对所有名称使用显式限定,我接受使用std :: name,我反对使用命名空间std进行
(我们有一个lisp解释器,该解释器具有自己的列表类型这样就可以肯定有冲突)。
对于其他名称空间,还必须考虑使用的命名约定。我知道一个使用名称空间(用于版本控制)和名称前缀的项目。然后执行
using namespace X
几乎是没有风险的,并且不执行该操作会导致看起来愚蠢的代码PrefixNS::pfxMyFunction(...)
。 std :: swap是最常见的情况:导入std :: swap,然后使用不合格的swap。如果没有,依赖于参数的查找将在类型的命名空间中找到足够的交换,如果没有,则退回到标准模板。 />在评论中,迈克尔·伯(Michael Burr)想知道冲突是否发生在现实世界中。这是一个真实的例子。我们的扩展语言是lisp方言。我们的解释器有一个包含文件lisp.h,其中包含typedef struct list {} list;
:
#include <list>
...
using std::list;
...
void foo(list const&) {}
所以我们这样修改:
#include <list>
#include "module.h"
...
using std::list;
...
void foo(list const&) {}
很好。一切正常。几个月后,“ module.h”被修改为包括“ list.h”。测试通过了。尚未以影响其ABI的方式修改“模块”,因此可以使用“引擎”库而无需重新编译其用户。集成测试还可以。新的“模块”发布。引擎的下一次编译在未修改其代码时中断。
评论
我认为使用名称空间是可以接受的受控情况之一是在发布代码中。简化可以简化页面的布局,并有助于将精力集中在暴露点上。缺点是它实际上并没有表现出很好的做法,因此我不会在初学者的书中使用它。
– AProgrammer
09年8月12日在9:24
我认为输入std ::是为了澄清而付出的很小的代价
– paoloricardo
09年8月12日上午10:13
@paoloricardo:另一方面,我认为std ::到处显示都是不必要的视觉混乱。
– Michael Burr
09年8月12日在16:46
@Michael:您付钱,您就做出选择!
– paoloricardo
09年8月12日在19:41
感谢您抽出宝贵时间添加遇到的问题的详细信息。
– Michael Burr
09年8月13日在16:28
#5 楼
如果您不存在与标准库和其他库的代码中名称冲突的风险,则可以使用:文档代码或存在名称冲突的风险,请使用其他方法:在代码中使用可以为您带来更大的安全性,但也许会使代码有些沉重...
#6 楼
using std::string;
和
using namespace std;
向全局名称空间添加了一些符号(一个或多个)。将符号添加到全局名称空间是您永远不应在头文件中执行的操作。您无法控制谁将包含您的标头,有很多标头包含其他标头(以及标头包含标头的标头等等)。
在实现(.cpp)文件中,此操作由您决定(只记得在所有#include指令之后执行此操作)。您只能破坏此特定文件中的代码,因此更易于管理和找出名称冲突的原因。如果您更喜欢在标识符前使用std::(或任何其他前缀,则项目中可能有很多名称空间),可以。如果您想将用于全局标识符的标识符添加到全局名称空间,就可以了。如果您想把整个名称空间放在脑子里:-),这取决于您。虽然效果仅限于单个编译单元,但是可以接受。
#7 楼
对我来说,我更喜欢在可能的情况下使用::
。std::list<int> iList;
我不想写:
希望使用C ++ 0x,我可以这样写:
for(std::list<int>::iterator i = iList.begin(); i != iList.end(); i++)
{
//
}
如果命名空间很长,
评论
@AraK:名称空间dir = boost :: filesystem;我猜这是一个别名吗?
– paoloricardo
09年8月12日在10:17
@paoloricardo:是的,这就是它。
–sbi
09年8月12日13:49
迭代器应该使用++ i而不是i ++进行递增,因为即使定义了迭代器,它也会创建不必要的迭代器临时副本。
– Felix Dombek
11年7月16日在8:16
#8 楼
您永远不要在标头中的名称空间范围内使用using namespace std
。另外,我想大多数程序员会怀疑他们何时看到不带vector
的string
或std::
,所以我认为using namespace std
更好。因此,我认为绝对不会存在。 如果您觉得必须,请使用
using namespace std
之类的声明添加本地。但是问自己:这有什么价值?一行代码只写一次(也许两次),但是却被读取了十,百或千次。与读取代码相比,通过添加using声明或指令节省的键入工作量很小。 考虑到这一点,十年前的一个项目中,我们决定使用所有名称空间的完整名称来明确限定所有标识符。起初看起来很尴尬的事情在两周内就变成了常规。现在,在整个公司的所有项目中,没有人再使用指令或声明了。 (除了一个例外,请参阅下文。)十年后的代码(几个MLoC)让我觉得我们做出了正确的决定。
我发现通常,那些反对禁止
using std::vector
的人通常没有为一个项目尝试过。那些尝试过的人通常会发现,比在很短的时间内使用指令/声明更好。 注意:唯一的例外是
using
,它是必需的(尤其是在通用代码中),以拾取无法放入using std::swap
名称空间的swap()
的重载(因为我们不允许放置std
函数进入此命名空间)。 评论
std :: swap的专业化将是一个完整的专业化-您不能对功能模板进行部分专业化。任何程序都可以部分规范任何标准库模板,只要该规范取决于用户定义的类型即可。
– CB Bailey
09年8月12日在10:54
@Charles:是的,您是对的,当然,没有FTPS。而且我可以在std中专门化模板,但不能重载。对不起,这个脑袋。我会改正这个帖子。
–sbi
2009年8月12日13:45
我不认为using namespace指令的目的是要进行输入。相反,这是为了使阅读更容易,因为正如您所说,该代码将必须被读取数十,数百或数千次。对于某些人来说,std ::杂乱无章,读起来容易得多。但这可能归结为个人的感知能力;有些人过滤std ::离开甚至需要它作为指导(例如衬线),其他人踩踏它并感觉就像在崎y不平的道路上。
–卢米
2011-12-27 12:36
@Lumi:无论您喜欢较短还是较长的散文都是主观的,但是前缀可以客观地增加代码的清晰度。
–sbi
2011-12-27 12:56
@sbi:不,那不是客观的。这取决于您是否认为std ::是有用的还是混乱的。更加混乱->不够清晰。
–约书亚·理查森(Joshua Richardson)
2013年9月4日在17:40
#9 楼
命名空间保留包含代码,以防止混淆和污染函数签名。 :#include <iostream>
#include <cmath> // Uses ::log, which would be the log() here if it were not in a namespace, see https://stackoverflow.com/questions/11892976/why-is-my-log-in-the-std-namespace
// Silently overrides std::log
//double log(double d) { return 420; }
namespace uniquename {
using namespace std; // So we don't have to waste space on std:: when not needed.
double log(double d) {
return 42;
}
int main() {
cout << "Our log: " << log(4.2) << endl;
cout << "Standard log: " << std::log(4.2);
return 0;
}
}
// Global wrapper for our contained code.
int main() {
return uniquename::main();
}
#10 楼
using namespace std
导入当前名称空间中std
命名空间的内容。因此,这样做的好处是您不必在该名称空间的所有函数前面键入std::
。但是,可能会发生具有具有相同名称功能的不同名称空间的情况。因此,您可能会结束不调用所需的调用的操作。在
std
中手动指定要导入的操作可以防止这种情况的发生,但是可能会导致在文件开头使用的列表很长。 ,有些开发人员会发现它很丑陋;)!个人而言,我个人宁愿每次使用函数时都指定名称空间,除非名称空间过长,在这种情况下,我会在编辑文件的开头。编辑:如另一个答案中所述,切勿将
using namespace
放入标头文件中,因为它会传播到包括该标头的所有文件,因此可能会产生不良行为。 br /> EDIT2:由于Charles的评论,更正了我的答案。
评论
使用命名空间std;将std名称空间的内容导入全局名称空间。它不会更改默认名称空间。在使用命名空间std之后在全局命名空间中定义某些内容不会神奇地将其放入std命名空间。
– CB Bailey
09年8月12日在9:14
抱歉,这不是我的意思。感谢您指出来,我将更正我的答案。
–Wookai
09年8月12日在9:26
伙计们:感谢您的答复。看来,通常来说,不使用“使用命名空间std”并避免产生潜在的歧义会更安全。总而言之,使用'std :: xxx'比在源文件的开头声明各种功能的列表更吸引我,因为它明确地表明了您的意图。
– paoloricardo
09年8月12日在9:41
Quote(除非名称空间太长)。您可以使用名称空间别名来提供帮助。 '命名空间Rv1 = Thor :: XML :: XPath :: Rules :: Light :: Version1;'注意别名并使用两个服从范围规则;
–马丁·约克
09年8月12日在14:47
#11 楼
就像在Java中,您可以使用可以包含java.util。*或简单地单独选择每个类一样,这取决于样式。请注意,您不希望在文件/广域范围的开始处出现一个using namespace std
,因为您会污染名称空间并可能发生冲突,从而破坏了名称空间。但是,如果您有一个使用大量STL的函数,则会使代码混乱,从而使逻辑中的前缀语法变得混乱,您可能应该考虑使用using namespace std
(使用各种类时)或单独使用using
(使用时)经常上几堂课。#12 楼
只要您使用的IDE不够灵活,无法显示或隐藏所需的确切信息,此讨论就将继续进行。这是因为您希望代码的外观取决于
创建源代码时,我更喜欢确切地看到我使用的是哪个类:是
std::string
还是BuzFlox::Obs::string
类?设计时在控制流中,我什至对变量的类型都不感兴趣,但我想重点关注
if
和while
和continue
。所以这是我的建议:
根据代码的读者和工具的功能,选择最容易阅读或提供最多信息的方式。
#13 楼
有几种方法可以解决此问题。第一:像您一样使用。
第二:执行
namespace S = std;
,减少2个字符。第三:请使用
static
。第四:请勿使用
std
所使用的名称。#14 楼
除了这里的许多正确答案外,我想说明一个经常被遗忘的细节:由于通用的编码和链接方案,许多开发人员似乎误解了C ++中的翻译单元的概念。对于我们大多数人来说,这很常见,.h文件是头文件,.cpp文件会产生实现细节,但这只是同意,而不是严格的标准规则。最终如何组合翻译单元将取决于您自己。因此,例如,使用UnityBuilds(将所有内容链接到一个翻译单元以提高速度和存储目的),您就不再可以依靠共同的同意,在.cpp文件中使用命名空间通常是可以的。有人可能会争辩说,UnityBuilds绕过了几种主要的C ++核心哲学,因此它们本身就是一个主题,但是尽管如此,在其他情况下仍可能出现类似的问题(例如,函数中包含本地)。顺便说一下,匿名命名空间的使用也出现了类似的问题。
由于过去这是我的问题,因此我想出了“内部准则”,以便在比例允许的情况下尽可能明确它。
#15 楼
每个优点和缺点的分别是什么?
离开std ::的唯一理由是,从理论上讲,您可以自己重新实现所有STL功能。然后您的功能可以从使用std :: vector切换到my :: vector,而无需更改代码。
评论
命名空间并不是真正设计为允许使用不同但等效的功能替换名称。它们旨在防止意外的名称冲突。
– Michael Burr
09年8月12日在17:35
是的,因此打破此用法的“ using”指令的唯一理由是允许您将函数切换到新的名称空间。
–马丁·贝克特(Martin Beckett)
09年8月12日在17:48
我认为您会发现很多程序员抱怨ass命名空间有什么痛苦,并且如果没有使用指令,他们希望将它们扔到窗外。据我所知,每种使用名称空间的语言都具有与using指令相似的功能,以便在您希望使用它们时避免使用它们。如果指令无用,为什么它们无处不在?
– Michael Burr
09年8月12日在19:11
我认为“使用”旨在让您切换到其他实现,而不是保存键入的3个字母。我喜欢使用“ std :: Foo”,因为它是我使用普通Foo的程序员合同,他们不必检查。我同意我不想键入“ com.microsoft.visual-studio.standard-library.numbers.int foo”,STL中的某些迭代器声明就是这样。 Python做得很好,它允许您从模块中引入经过修饰或未经修饰的函数集。
–马丁·贝克特(Martin Beckett)
09年8月12日在19:30
#16 楼
为什么不例如typedef std::vector<int> ints_t;
ints_t ints1;
....
ints_t ints2;
而不是笨拙的
std::vector<int> ints1;
...
std::vector<int> ints2;
我发现它更具可读性,我的编码标准。
您甚至可以使用它为读者提供一些语义信息。例如,考虑函数原型
void getHistorgram(std::vector<unsigned int>&, std::vector<unsigned int>&);
哪个是返回值?
评论
另请参见如何在C ++中正确使用名称空间?为什么“使用命名空间标准”被认为是不好的做法?
以及如何解决C ++命名空间与全局函数之间的名称冲突?