别人告诉我,用代码编写using namespace std是错误的,我应该直接使用std::cout和std::cin。
为什么using namespace std被认为是一种不好的做法?它是否效率低下,或者是否存在声明不明确变量(与std命名空间中的函数同名的变量)的风险?它会影响性能吗?
- 别忘了你可以这样做:"使用std::cout";这意味着你不必输入std::cout,但不要同时输入整个std名称空间。
- @一个付费的书呆子google styleguide.googlecode.com/svn/trunk/…链接不再有效。看起来新的链接是google.github.io/styleguide/cppguide.html其他的C++_功能
- 在头文件的文件范围内使用"using namespace std"尤其糟糕。毕竟,在文件作用域includes中使用它在源文件(*.cpp)中并没有那么糟糕,因为它的效果仅限于一个翻译单元。更没有问题的是在函数或类中使用它,因为它的效果仅限于函数或类范围。
- 我不鼓励使用指令,但是对于特定的名称空间,如std::literals::chrono_literals、Poco::Data:Keywords、Poco::Units和处理文本或可读性技巧的内容。每当它在头文件或实现文件中时。我想在函数范围内可能没问题,但是除了文字和其他东西之外,它是没用的。
- @sh-你为什么建议使用"使用名称空间标准"是"特别糟糕"的?
- @乔恩:特别是与名称空间std无关。我的重点是"在头文件的文件范围内"。建议:不要在头文件的文件范围内使用"使用名称空间"(std或其他)。可以在实现文件中使用它。抱歉含糊不清。
- 使用它是错误的,因为代码看起来比实际情况更困难,所以初学者会更快地退出编程。
这与表演一点关系都没有。但是考虑一下:您使用的是两个名为foo和bar的库:
1 2
| using namespace foo;
using namespace bar; |
一切正常,你可以从FOO打电话给Blah(),从酒吧打电话给Quux(),没有问题。但是有一天你升级到了新版本的foo 2.0,它现在提供了一个名为Quux()的函数。现在您遇到了一个冲突:foo 2.0和bar都将Quux()导入到全局命名空间中。这需要花费一些精力来修复,特别是当函数参数恰好匹配时。
如果你使用了foo::Blah()和bar::Quux(),那么引入foo::Quux()就不是什么大事了。
- 我一直很喜欢python的"import big-honkin-name as bhn",这样你就可以使用"bhn.something"而不是"big-honkin-name.something",这真的减少了输入量。C++有类似的东西吗?
- @pax名称空间io=boost::filesystem;
- 我认为说这是"一些努力去解决"是夸大了事实。您将没有新foo::quux的实例,因此只需消除当前对bar::quux的所有使用。
- 是否有明智的人会创建一个库,其中不合格名称与std类型冲突的类型?
- @马蒂特:事情可能比"不得不修复"更糟。(参见我的答案:stackoverflow.com/questions/1452721/1453605 1453605)。
- @Erikkallen:std lib已经取了数百(甚至数千)个名字,其中许多名字非常流行和常见(error、list、sort,这是iirc将其放入自己的名称空间的一个重要原因。
- 要复制python的"import longnamespace as spc"行为,只需使用define。我看不出有什么问题。
- @toma:#define的问题在于它不局限于名称空间,而是对整个代码基进行遍历。名称空间别名就是您想要的。
- 对于记录,名称空间别名是using namespace bhn = big_honkin_name;,而不是新名称空间中的defines或using语句。
- 为什么C++中的问题比C语言中的问题更严重呢?据我所知,C有着完全相同的潜在问题,但没有人会梦想使用(例如)Company.Product.Component.Foo,而不仅仅是Foo。
- @ Kragen:C++的命名空间很大,而C是相对粒度的。(就记录而言,我更喜欢C中至少部分限定名,但这是一个完全不同的主题…)
- "ErkkalEN可能不是,但是假设您想把C++ 03的程序移植到C++ 11,并发现STD添加了一些东西。
- @当然,考虑到它包含了像vector、set或transform这样的好的和普通的名字,而且无论如何,没有人应该盲目使用using namespace std。当然,命名您的东西my_complex_vector_type或perform_a_transformation或set_this_value,仅仅是出于对std名称的恐惧,这是垃圾,而且无论如何都会完全失效名称空间的用途。
- @这里有点无知…您所说的boost::filesystem是什么意思?使用IO namesapce会提高性能吗?对不起,如果这听起来很傻的话:)
- @伊索尔。Arak正在谈论名称空间别名:link
- 众所周知的C++库ErkkalEnApple有很多与IoSoW相冲突的东西。
- 所以,只要您只使用一个using namespace,并且它不在头文件中,您应该没事吧??
- @不幸的是,有一些库不使用名称空间,因此即使是一个using namespace也会造成问题。当然,如果您使用多个不使用名称空间的库,那么您就是S.O.L。
- @如果2000年有人在标准库之前写了一个叫做unordered_map的类,那会怎么样?
- 所以…使用名称空间别名被认为是避免写入整个名称空间的最佳方法?另外,@bill评论了using namespace std::cout和using namespace std::cin--有人看到这方面的任何潜在问题吗,还是认为这是安全的?在我看来,这可以避免"冲突的名称空间"问题,同时允许我编写cout << some code或cin >> some code,并且只保留对使用较少的std名称空间调用的std::调用。
- 但是为什么有人会创建一个称为"cout"或"cin"的函数呢??我认为这都是胡说八道,我将永远使用名称空间std;因为我不认为有人会创建一个名为"cout"、"cin"的函数或其他类似的著名函数。
- @Edwardblack cout和cin可能不是最好的例子,但有些名称更常见,可以被不同的库用来表示不同的事物。例如,有一个std::vector、一个boost::mpl::vector、一个boost::numeric::ublas::vector,它们都是非常不同的,但都应该叫vector。
- @EdwardBlack性病中使用的其他常用名称示例有system、time、pair、map、min、merge…你是说没有人应该在他们的图书馆里使用这些名字吗?
- 为什么会有人使用"系统"或"时间"?
- @爱德华德布莱克:假设你从一家证券交易所得到了一些长协议文件,其中"系统"标识了一些关于交易所的信息;如果你不使用相同的标识符,你会使文档中的伪代码的采用和比较变得复杂,使用文档的索引来查找相关的信息,这是你可以谈论的常用术语。就数据问题等向参加交流的人。当然,关键字也存在同样的问题,但这并不是不完全匹配的原因。
- @我认为你是对的,假设你是项目中唯一的程序员,当你升级到foo 2.0时你意识到了冲突。
- -1:这个答案解释了未来可能需要的清理任务,但不是为什么这是个坏主意。以名称空间冲突结束也会在其他语言中发生,并且只要编译器给您一个明确的提示,通常情况下这不是什么大问题。
- 使用函数的限定名可防止ADL。因此,不可能有一个明确的"不使用using规则"。
- @汤普森:这个答案确实概括了可能发生的最好的情况:编译器不再编译您的代码。没有任何伤害。SBI的另一个回答是,如果编译器继续编译您的代码,那么情况会更糟。但语义学改变了。它静默地编译您从未打算编写的代码。现在这很糟糕。
- @iInspectable我在对SDI答案的评论中添加了更多关于这个的信息。历史上,这是个问题。但是,现代编译器在这种情况下会发出警告或错误。也就是说,不,编译器不会静默编译,它会特别出错"对字符串的引用是不明确的"。
- 似乎是对一个非常罕见的案件,很容易修复防御实践。在所有导致错误的事情中,std名称空间冲突的排名必须非常低。防御措施是有代价的。这不是一件容易的事。
- @它的作用是减少输入,使代码更具可读性。
- 我不会认为这是一个问题,因为您得到编译错误,您可以修复它。当编译器开始静默地使用错误的函数时,可能会发生真正的问题。例如,如果使用bar::Quux(unsigned int),然后添加foo::Quux(int)。
- 我对这个答案投了反对票,因为我非常不相信图书馆实际上将它们的函数命名为与std中的函数相同的函数。我也会继续使用它。不需要进行任何修复,只需要重命名。
- 非常不相信?哦,孩子!你从没听说过Boost,对吧?std::filesystem和boost::filesystem,std::error_code和boost::system::error_code,std::chrono,boost::chrono,std::mt19937和boost::random::mt19937等等
- @齐马诺-看得更远。你怎么知道在将来新事物不会作为增强添加到std中,这与你已经拥有的代码或库相冲突?
- @帕西迪亚布洛:现在,埃多克斯一〔1〕出现了,可以做同样的事情。
- @公平地说,这有点倒退——这更像格雷戈所说的,他们先是得到提升,然后被采用到std中,因为他们非常有用。
我同意格雷格写的所有东西,但我想补充一句:它甚至可能比格雷格说的更糟!
库foo 2.0可以引入一个函数,Quux(),对于您对Quux()的一些调用来说,这个函数显然比您多年来调用的bar::Quux()代码更匹配。然后你的代码仍然在编译,但是它会悄悄地调用错误的函数,上帝知道什么。这是最坏的情况。
记住,std名称空间有大量的标识符,其中许多标识符是非常常见的(如list、sort、string、iterator等),它们也很可能出现在其他代码中。
如果您认为这不太可能:在给出这个答案半年后,这里有一个关于堆栈溢出的问题,在哪里发生了几乎完全正确的事情(由于省略了std::前缀而调用了错误的函数)。这是另一个更近的例子。所以这是一个真正的问题。
这里还有一个数据点:很多很多年前,我还发现在标准库的所有内容前面加上std::的前缀是很烦人的。然后,我在一个项目中工作,在这个项目开始时决定,除了函数范围之外,using指令和声明都是禁止的。你猜怎么着?我们中的大多数人花了几周时间习惯于写前缀,几周之后,我们中的大多数人甚至同意它实际上使代码更易于阅读。这是有原因的:不管你喜欢短文还是长文都是主观的,但是前缀客观地增加了代码的清晰度。不仅编译器,而且您也发现更容易看到引用了哪个标识符。
在十年的时间里,这个项目增加到了几百万行代码。由于这些讨论反复出现,我曾经好奇(允许的)功能范围using在项目中实际使用的频率。我找到了它的来源,只找到了一两打使用它的地方。对我来说,这表明,一旦尝试过,开发人员发现std::不够痛苦,即使每100 kloc使用一次指令,即使在允许使用的地方。
最重要的是:明确地预加前缀不会造成任何伤害,很少需要习惯,并且有客观的优势。特别是,它使代码更容易被编译器和人类读者解释——这可能是编写代码时的主要目标。
- 它会严重损害您可以在一行中打包的代码的密度。您最终会以一种非常冗长的方式编写代码,这会降低可读性。就我个人而言,我认为更短(但不太短)的代码更易于阅读(因为要阅读的内容更少,而要分心的内容也更少)。
- @谎言:不管你喜欢短文还是长文都是一种主观偏好。(我见过真正喜欢长标识符的开发人员,尽管这意味着即使是最简单的函数调用,他们也必须拆分行。)是否确切地看到引用哪个标识符(otoh)是一个客观的标准。我以前和你分享过你的POV,被迫尝了尝另一边的味道,再也没有回头看。
- @SBI:虽然我不反对非std::标识符,但是能够看到名称的来源可以提高可读性。我认为std::表示是多余的。尽管它是一个客观的标准,但它有着表面的价值,因为你应该期望任何有能力的C++程序员知道C++标准库,并且你不会期望任何明智的程序员会故意用一个标准的库名称来冲突名字。就我个人而言,我把using namespace std放在我的所有代码上;尽管我保守地使用其他名称空间,这取决于使用频率。
- 猜想你错过了过去的日子前,C++有一个标准的EDOCX1×3类,似乎每个图书馆都有自己的。告诉你什么:我们会继续用std::编写代码,当你浏览时,你可以通过grep -v std:: | vim运行我们的代码。或者你可以教你的编辑std::是一个关键字,它的颜色和背景色相同。不管怎样。
- @谎言:"我认为std::的表示是多余的。"你反对输入完整标识符的主要论点,即它们增加了标识符的长度,将很难适用于std::。但即便如此,我还是不同意。看看这个问题的原因。
- @SBI:它们更适用于std::,因为它们的使用非常频繁,至少在我的代码中是如此。std::cout、std::cin和std::endl尤其是最淫秽的罪犯。对于向量/迭代器,我会编写typedef。否则,你最终会得到std::vector::iterator。您提到的问题是,有人用与标准库函数相同的名称命名了一个函数;我认为您同意使用&*ii的解决方案是荒谬的,但是我改变距离来构造只是稍微不那么荒谬。更好的解决方案是重命名Distance()。
- @谎言:"你提到的问题,是因为有人命名了一个与标准库函数同名的函数",这就是问题所在!你打算怎么避免呢?在std名称空间中,有数百(如果不是数千)个标识符,其中非常流行的标识符。有那么多,你简直无法避免与他们发生冲突。这就是他们都在江户的原因。把using namespace std添加到文件中,迟早会遇到这样的问题。
- 我认为std::一点都不有害。它包含非常重要的信息(即"后面的内容是标准库的一部分",它仍然是一个非常短和紧凑的前缀。大多数时候,这根本没问题。有时,您有几行代码需要大量引用std名称空间中的特定符号,然后在该特定范围内的using语句可以很好地解决问题。但在一般情况下,它不是噪音,它除了传递模棱两可的信息外,还传递有价值的信息。
- @SBI,@JALF:这会弄脏你的代码,我不会因此而接受"不"。
- @SBI:因为我看到有人爱上了必须到处写多余的std::的束缚和约束。我再也不能相信他的理性了。
- 对于源文件中的import namespace std,这似乎是一个合理的折衷方案,但不导入任何其他内容。这样就避免了对那些可能是最经常调用的库符号进行前缀,同时也避免了名称空间冲突的可能性。
- @ RjOllos:它在C++中被拼写为EDOCX1 2。撇开这一点:是的,你可以做各种妥协,但我的观点是1)你仍然会遇到问题(stackoverflow.com/questions/2879555/2880136),2)当代码更明确(因为它确切地说明了它的作用)时,客观上更容易阅读,3)完全没有必要,因为缩写只是一个habi你不能离开。见鬼,有很多人在写Java,有些人甚至用艾达这样的语言编写代码,这真的是一种健谈的语言。我尽量不必输入StringUtilities::。但是std::呢?
- 每当我看到std::时,我就知道它是来自std::的,而不必去想它。如果我单独看到string或list或map,我会有点奇怪。
- @Lieryan这是三个角色。利益大于成本,犹如大象大于苍蝇。
- @然后,利瑞安好运地写了一个几何图书馆,却从来没有命名过vector、transform或distance。这些只是标准库中使用的许多常见名称的示例。建议不要使用恐惧或对C++的组成部分的名称空间特征的偏颇意见,这是相反的。
- "明确地加前缀不会造成任何伤害",除非它破坏了参数相关查找(ADL),例如swap。这里也可以看到。在这些情况下,using std::swap比直接调用std::swap要好。
- @当然,和任何规则一样,也有例外。但这并不能改变这样一个事实:一般来说,using namesapce std;被认为是一种不好的做法。
- 这听起来很愚蠢:直到现在我才意识到确切知道你的程序中到底发生了什么的重要性。我的老师总是说,"你不需要知道",每当问一个关于幕后"东西"的问题——总是让我不安的事情。但是,格雷格的回答完全证明了我的好奇心,需要知道发生了什么。
- the prefixes objectively add clarity to the code这是对"客观"事物的观点替代。根据这种逻辑,boost::numeric::ublas::vector_range,>是最易读和最清晰的东西。另外,这个例子:To me this indicates that, once tried, developers didn't find std:: painful enough to employ using directives even once every 100kLoC even where it was allowed to be used.也是相当主观的。换句话说,投反对票。
- 听起来,编译器警告可能有助于识别对于名称相同但名称空间不同的函数发生更好匹配的情况。这至少会消除部分问题。
- @亚历山德罗德:你如何建议编译器发现你的调用在上周以不同的重载结束?因为这是一个很可能的情况。
- 哦,不,我的意思是更简单的检查——只是被调用的某个函数有来自不同名称空间的重载(不管参数是否匹配)。既然我们讨论的是两个函数同时可见的情况…(当然,如果有一个完整的开关,也就是说,一个"使用名称空间"被另一个替换了,那将没有帮助)。
- @但是ADL一直在调用其他名称空间中的函数!例如,每次添加两个std::string实例时。或者调用在其他命名空间中定义的任何其他运算符。
- 如果在每个标准标识符之前写"STD::"是"没什么大不了的",为什么C++会引入命名空间呢?他们可以用C样式的前缀定义所有的标准标识符,并使用诸如std_-string、std_-cout等名称…以避免名称冲突。名称空间的关键是,如果要使用这些符号,可以编写"using",但如果需要,仍然可以消除歧义(重点是if)。如果不使用"using",名称空间不会比C样式的标识符前缀更好。
- @布兰登:你如何让ADL使用前缀而不是名称空间?您如何调用swap(),以便获取任何用户提供的版本?您将如何使用带前缀的std::placeholders?(你在批评我之前仔细地读了我的答案,对吗?所以你读了我说的"除了函数作用域",不是吗?
- 我同意一般的说法,即using namespace std;可能有害,但我不同意您的一些观点:首先是关于您的数据点:仅仅因为开发人员不在函数范围内使用using namespace std;,并不意味着,如果允许的话,他们不会在文件范围内使用它。如果你的函数很短,那么在函数范围的情况下,"价格-效益比"会更糟。第二个关于可读性的问题:你在一篇评论中写道,"客观上,代码在更明确的时候更可读"。
- …我不认为这很容易:在任何地方添加std::,都会使相关部分更加分散,使代码更具层次性,并且在某些/许多情况下,不会添加任何相关信息。这实际上使阅读变得更加困难,这取决于情况和读者,而这种影响实际上更大。您可能也不会在一系列数学运算中添加不必要的括号,尽管这样做更为明确。
- @mikemb:stackoverflow.com/questions/1452721/&hellip;
- 当一个文件中使用相同的名称并且出现在多个命名空间中时,是否没有编译器标志来警告/错误,而不考虑专门化?这似乎是编写编译器的人所能解释的。
- @滑步:不,很可能没有,如果有的话,你会对他们的结果感到非常惊讶。在C++命名空间编程之前,我可以向您保证,在每个非平凡的C++项目中都有几十个相同的标识符。冲突在当时是个真正的问题。毕竟,这就是名称空间被发明的原因。如果编译器对此发出了警告,那么我们就回到第一格,在这里我们不能在代码的不同部分使用相同的标识符。
- @有意义的sbi,但是编译器警告只对当前冲突的内容有意义-根命名空间中的标识符,或者在您的using中的标识符,并且只对您在给定源文件中实际使用的标识符有意义(警告是关于用法,而不是声明)。当一个不需要的冲突出现时,你应该知道杀死文件中的一个using,并明确表示出来。也许在C++的LIBS中命名空间更加臃肿,但除此之外,我想我看不出这与C语言或Java中的命名空间有什么不同。
- @简而言之,我们需要的不是"相同的标识符错误",而是"冲突警告"。我想我们不应该依靠编译器来选择。
- @弗兰克林,对。我假设它的工作方式与Clang的其他重新定义警告类似,它会向您提供与之冲突的所有实例的列表。如果它很好地集成到您的IDE中(比如clang和xcode)。
- @Franklinyu证明clang确实做到了这一点——它给了我一个很难"引用"的"string"是含糊不清的"错误"。这里的证据:cl.ly/eruf这是使用一个有点过时的clang版本(xcode 5.1.1的Apple llvm版本5.1(clang-503.0.40)(基于llvm 3.4svn)),所以如果你使用clang,很可能你已经从这个保护中受益。|对不起,斯比,我现在必须投反对票。历史上这是个大问题,当然。但阿法奇已经不在了。
- @slippd.汤普森,我还有一个函数冲突的例子。我们看到它不会抱怨相同的标识符(或者第11行会有一个错误),即使它们都被导入根命名空间(或者第18行会有一个错误),也不会抱怨,因为实际上我可以使用第22行和第23行的显式命名空间安全地访问它们(尽管没有建议)。|因此@sbi,我也不喜欢在全球范围内使用using namespace std;,但它不会导致现代编译器的问题,所以对我的否决表示抱歉。
- 我真的喜欢在尽可能小的范围内引用东西,就像在第一次使用的站点声明变量一样,所以我不需要顶级的using namespace ns;,但是我发现在功能级别using std::cout;相当优雅。
- 我相信每个人都明白这一点,没有必要大喊大叫。
- 故事的士气->根本不要使用std;-)。
将using namespace放入类的头文件中的问题是,它强制任何想要使用类(通过包括头文件)的人也"使用"(即查看所有内容)那些其他名称空间。
但是,您可以在(private).cpp文件中随意放置using语句。
注意,有些人不同意我这样说的"感觉自由"——因为尽管cpp文件中的using语句比头文件中的语句更好(因为它不会影响包含头文件的人),但他们认为它仍然不好(因为根据代码的不同,它可能会使类的实现更难维护)。.本常见问题解答主题说明:
The using-directive exists for legacy C++ code and to ease the transition to namespaces, but you probably shouldn’t use it on a regular basis, at least not in your new C++ code.
常见问题解答提出了两种备选方案:
使用声明:
1 2
| using std::cout; // a using-declaration lets you use cout without qualification
cout <<"Values:"; |
只需输入标准:
- 把它放在一个.cpp文件中比放在一个头文件中不那么糟糕,但是在可维护性方面,问题仍然存在。当使用的代码/库/ C++标准被修改时,两个同名函数会发生冲突。
- 你试过这个吗?因为using namespace指令不会传递到另一个文件中。(GCC 4.8 +)
- @zackery.fix,"apple llvm version 7.0.2(clang-700.1.81)"将using namespace std;从头文件传播到源文件,我验证了gcc没有。所以至少在头中使用"using"指令是有风险的。
- 赞成。。我不使用llvm或clang,这也不是标准的方法。
- 你真的不应该告诉人们在.cpp文件中使用名称空间std"感觉自由"。@É;蒂安是对的。
- 一个危险,即使在"私有"cpp文件中,也会在以后添加另一个头来实现一个新函数,并且会破坏文件中其他地方的"稳定"代码。举个例子。不要这样做。"不管是不是私有的,头还是cpp,只是不要。
- @但是他们是"自由"的。
- @轻量级赛马Sinorbit:如果Chrisw用引号写了"但是你可以"这样做",这个建议不会那么糟糕。在.cpp文件中,人们当然不应该感觉到224对using namespace std的投票是自由的。
- @最近的编辑适合吗?
- @克丽丝:这基本上与你的"感觉自由"的说法相矛盾,但现在对我来说已经足够好了。
- @但是,他们完全可以这样做(这次省略了报价,所以你不能歪曲我的陈述)。你不能告诉224个人他们能做什么,不能做什么…
- @轻微的雷射性脑损伤:你在做一个认识论的争论。他们是自由的,因为我们不能禁止他们吗?或者他们不自由,因为他们必须考虑和小心它有消极的再授权吗?我会说选项2。不管怎样,他们不应该"感到自由",即使他们"有自由"这样做。
- @埃因波克勒姆:我根本就没有"争论"——我只是指出,无论你喜欢与否,你都不能剥夺我的自由或任何其他人的自由,或我自由写作的能力。你根本无法控制这件事。那么,你为什么总是说人们不应该自由地做他们想做的事?这没道理,你应该停下来…
- @光明赛马Sinorbit:我们正在讨论一个答案,关于人们应该和不应该做什么。没有人会剥夺任何人做任何事的自由。
- 我在cpp文件中使用了std(取决于项目),不过我避免在任何头文件中这样做。
- @zackery.fix,franklinyu如果编译器不以某种方式将任何一行代码从包含的头文件"传播"到包含它的源文件,那么编译器就完全崩溃了。包含是文本的;它与语义无关,不能(必须)修改语义。我发现几乎不可能相信你在评论中所说的话,我唯一能让自己这么做的方法就是得出这样一个结论:这是一个非常糟糕的编译器bug,一定已经被修复了。
- 请放心,请注意,您可能会引入由多个库的名称空间污染引起的命名冲突。
我最近遇到一个有关Visual Studio 2010的投诉。结果发现几乎所有的源文件都有这两行:
1 2
| using namespace std;
using namespace boost; |
C++0x标准中有很多Boost特性,VisualNasnStudio & Nbsp 2010有很多C++ 0x特性,所以这些程序突然没有编译。
因此,避免using namespace X;是一种未来的校对方式,确保对正在使用的库和/或头文件进行更改不会破坏程序。
- 这个。Boost和STD有很多重叠,尤其是C++ 11之后。
- 我做过一次,并以一种艰苦的方式吸取了教训。现在,我从不在函数定义之外使用using,而且很少使用using namespace。
短版本:不要在头文件中使用全局声明或指令。在实现文件中随意使用它们。下面是萨特和Andrei Alexandrescu关于C++编码标准中的这个问题(强调强调我的):
Summary
Namespace usings are for your convenience, not for you to inflict on others: Never write a using declaration or a using directive before an #include directive.
Corollary: In header files, don’t write namespace-level using directives or using declarations; instead, explicitly namespace-qualify all names. (The second rule follows from the first, because headers can never know what other header #includes might appear after them.)
Discussion
In short: You can and should use namespace using declarations and directives liberally in your implementation files after #include directives and feel good about it. Despite repeated assertions to the contrary, namespace using declarations and directives are not evil and they do not defeat the purpose of namespaces. Rather, they are what make namespaces usable.
- 可悲的是,这种理智的引导被错误的答案所掩埋。
- 这里还有一个程序员的意见,但是我完全同意"EDOCX1"(22)这个词不应该出现在标题中的说法,但我不太相信可以在代码中任意位置放置using namespace xyz;,特别是如果xyz是std。我使用using std::vector;形式,因为它只将名称空间中的单个元素拉入伪全局范围,因此导致冲突的风险要小得多。
- @在轨道上的轻量级比赛,你当然有权得到你的意见。如果有人试图解释为什么你不同意这个答案中给出的建议,会更有帮助。特别是,如果"使用"名称空间不好,那么理解名称空间的意义是什么是很有趣的?为什么不把事情命名为std_cout而不是std::cout…C++/命名空间的创建者在创建它们时一定有一些想法。
- @Nyholku:不需要-其他大多数答案都给出了和我一样的理由。另外,请毫不犹豫地注意":)"这句话是我在评论中附加的!我没有说名称空间是坏的。
- 是的,我注意到了:)但是在我看来,大多数的回答(违背了这个明智的建议)都是错误的(我没有统计出现在大多数人是什么)。如果您同意名称空间"不错",那么如果您不同意这个答案,您可能会说您认为它们在哪里是合适的?
不应该在全局范围内使用using指令,尤其是在头中。但是,在某些情况下,即使在头文件中也适用:
1 2 3 4 5 6
| template <typename FloatType> inline
FloatType compute_something(FloatType x)
{
using namespace std; //no problem since scope is limited
return exp(x) * (sin(x) - cos(x * 2) + sin(x * 3) - cos(x * 4));
} |
这优于明确的资格(std::sin、std::cos…)因为它较短,并且能够处理用户定义的浮点类型(通过依赖于参数的查找)。
- 对不起,我强烈反对。
- @比利:没有其他方法可以支持调用userlib::cos(userlib::superent)。每个功能都有用途。
- @赞:当然有。using std::cos;、using std::sin等。但问题是,任何设计良好的userlib都会将它们的sin和cos放在自己的名称空间中,所以这对您没有帮助。(除非在这个模板之前有一个using namespace userlib,这和using namespace std一样糟糕,而且范围也不有限。)此外,我见过的唯一这样的功能就是swap,在这种情况下,我建议创建一个std::swap的模板专门化,并避免整个问题。
- @比利:有时候你得超载交换(比如当你需要它的时候你自己的容器)。但即使这样,本地using声明也比using指令要好得多。
- @SBI:我不明白当模板专门化执行相同的工作,并且不需要调用方记住激活ADL时,为什么需要重载。(不符合条件的掉期)
- @billyonel:template void swap(MyContainer&, MyContainer&)(没有函数模板部分专用化(ftps),因此有时需要使用重载。
- @比利约内尔:你的(7次投赞成票!)评论是错误的——你所描述的情况正是ADL设计要涵盖的内容。简而言之,如果x有一个或多个"关联的名称空间"(例如,如果它是在namespace userlib中定义的),那么任何看起来像cos(x)的函数调用都将另外在这些名称空间中查找,而不需要任何using namespace userlib;预先。Zan Lynx是正确的(C++名字查找是拜占庭……)
- 我宁愿选择using std::sin; using std::cos; using std::exp;,而不是using namespace std;。您可以获得相同的收益,而不会有任何将std::*倾卸到函数中的风险。
不要在全球范围内使用它
只有在全球使用时才被认为是"坏"的。因为:
- 您使正在编程的名称空间混乱。
- 当您使用多个using namespace xyz时,读者将很难看到特定标识符来自何处。
- 对于您的源代码的其他读者来说,无论什么是正确的,对于最经常阅读它的人来说,都是正确的:您自己。一两年后再来看看……
- 如果你只谈论EDCOX1,1,你可能不知道你抓取的所有东西,当你添加另一个EDCOX1,2,或者移动到一个新的C++版本,你可能会得到你不知道的名字冲突。
你可以在本地使用
继续在本地(几乎)免费使用它。当然,这会阻止你重复std::,重复也很糟糕。
本地使用的成语
在C++ 03中有一个成语——样板代码——用于为类实现EDCOX1×4函数。有人建议您实际使用本地using namespace std--或至少使用using std::swap:
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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的实现,以发现并选择潜在的过载。
- "std::swap的实现被更改以查找潜在的重载并选择它。"—什么?你确定吗?虽然在第一个地方提供一个自定义EDCOX1的2度是正确的,在C++ 11中不再重要,因为EDCOX1×3本身本身更灵活(使用移动语义)。但是,std::swap会自动选择您自己的自定义交换,这对我来说是全新的(我不太相信)。
- @我想是的,是的。我在某个地方读过这个。我们可以一直问霍华德,他应该知道。我现在在挖…
- @Christianrau现在找不到明确的链接(需要回去工作),但我找到了N3490和N1252
- 即使在交换的情况下,更清晰(谢天谢地更常见)的习惯用法是写using std::swap;,而不是using namespace std;。更具体的习惯用法具有更少的副作用,因此使代码更易于维护。
- @阿德里安麦卡锡,我知道,即使与非惯用代码有关,using std::swap惯用语也可用。但我同意,当你100%地控制着源头的时候,最好具体点。
- 最后一句是错的。在C++ 11中,STD交换的两步被正式称为正确调用swap的方法,并且改变了标准中的其他地方,称其称为swap那样(N.B.如上所述,EDCOX1×7是正确的方式,而不是EDCOX1〔11〕)。但江户十一〔3〕本身并没有改变,找别的江户十一〔2〕使用。如果调用std::swap,则使用std::swap。
- 不过,在本地键入using std::swap可能更明智,在创建自文档代码的同时减少本地命名空间。您很少对整个std名称空间感兴趣,所以只需挑选您感兴趣的部分。
- "当您使用多个using namespace xyz时,读者很难看到特定标识符的来源。"是的,就像编译器一样
- @G_的"是的,就像编译器一样",甚至在没有名字冲突的情况下。人类读者会有更多的困难。
如果导入正确的头文件,则在全局范围内突然出现名称,如hex、left、plus或count。如果您不知道std::包含这些名称,这可能会令人惊讶。如果您还尝试在本地使用这些名称,可能会导致相当多的混淆。
如果所有标准的东西都在自己的名称空间中,那么就不必担心与代码或其他库的名称冲突。
- +1更不用说distance。尽管如此,我还是更喜欢非限定名,因为这增加了我的可读性。另外,我认为事实上,我们通常不限定口头演讲的内容,并且愿意花时间解决可能存在的歧义,这意味着能够理解一个人在没有限定条件的情况下所说的话是有价值的,并且适用于源代码,这意味着它的结构方式是明确的,甚至是机智的。小时资格。
- 公平地说,如果你不包括,那么你就没有大部分的这些。不过,说得对。
经验丰富的程序员使用任何能解决他们问题的方法,避免任何能产生新问题的方法,并且出于这个确切的原因,他们避免使用头文件级别的指令。
经验丰富的程序员还试图避免对源文件中的名称进行完全限定。这样做的一个次要原因是,除非有充分的理由,否则在代码足够少的情况下编写更多的代码是不明智的。这主要是因为关闭了依赖于参数的查找(ADL)。
这些好理由是什么?有时程序员明确地想关闭ADL,而有时他们想消除歧义。
所以下面是可以的:
在函数实现中使用指令和声明的函数级
在源文件中使用声明的源文件级别
(有时)使用指令的源文件级别
另一个原因是惊喜。
如果我看到cout << blah,而不是std::cout << blah
我想这是什么东西?这是正常的cout吗?有什么特别的吗?
- 这是个笑话吗?我真的说不出来。如果不是这样的话,我个人会认为这是正常的"不能",除非你不信任代码,否则这将是一种超越主流的代码味道,我的……。如果你不信任代码,那你为什么要首先使用它呢?注意,我不是说"相信一切!"但是,如果你正在处理一些来自Github的知名库或者其他什么的话,这看起来也有点牵强。
- @Brentrittenhouse cout是一个坏例子,因为每个人都认识到它。但想象一下,在一个金融应用程序中,EDOCX1[1]。在指定日期买卖某物是合同吗?不,不是。如果代码说std::future,你就不会那么容易混淆。
- @Brentrittenhouse也许是个不好的例子,至少有四个不同的图书馆可以做到。可能是"标准图书馆吗?LISSTDC + +?STL?还有别的吗?"不,并不是每个人都知道性病:至少从本质上讲,我们收到的7个新工人中有6个不知道。因为教育课程不使用教育课程。我得把印刷品赶走。或debugs()-从qt。
我同意它不应该在全球范围内使用,但是在本地使用并不那么邪恶,就像在namespace中那样。下面是一个"C++编程语言"的例子:
1 2 3 4 5 6 7 8 9
| namespace My_lib {
using namespace His_lib; // everything from His_lib
using namespace Her_lib; // everything from Her_lib
using His_lib::String; // resolve potential clash in favor of His_lib
using Her_lib::Vector; // resolve potential clash in favor of Her_lib
} |
在这个例子中,我们解决了可能的名称冲突和由它们的组成引起的歧义。
其中明确声明的名称(包括使用诸如His_lib::String等声明声明声明的名称)优先于使用指令(using namespace Her_lib在另一个作用域中访问的名称。
我也认为这是一种不好的做法。为什么?就在一天,我认为名称空间的功能是划分东西,所以我不应该把所有东西都扔到一个全局包中。但是,如果我经常使用"cout"和"cin",我会在cpp文件中写入:using std::cout; using std::cin;(从未在头文件中使用,因为它与#include一起传播)。我认为没有一个理智的人会说出一条河流的名字:cout或cin。;)
很高兴看到代码并知道它的作用。如果我看到std::cout,我知道那是std库的cout流。如果我看到cout,我就不知道了。它可以是std库的cout流。或者在同一个函数中,可能有一个int cout = 0;10行更高。或者该文件中名为cout的static变量。它可以是任何东西。
现在以一百万行代码为基础,这并不是特别大,你在搜索一个bug,这意味着你知道在这一百万行中有一行代码不能做它应该做的。cout << 1;可以读取一个名为cout的static int,将其左移一位,并丢弃结果。找虫子,我得检查一下。你知道我真的很喜欢看std::cout吗?
如果你是一名教师,而且从不需要为生活而写和维护任何代码,那么这是其中一个看起来非常好的主意。我喜欢在以下地方看到代码:(1)我知道它做什么;(2)我相信编写代码的人知道它做什么。
- 你怎么知道"std::cout<<1"不是在std名称空间中读取一个名为cout的静态in t,将其移位一次并丢弃结果?另外,您如何知道"<<"是什么;)????…似乎这个答案是不好的数据点,避免"使用"。
- 如果有人将std::重新定义为整数,那么您的问题不是技术性的,而是社会性的——有人支持您。(您可能还应该检查所有的头文件,例如define true false等)
- 当我看到cout时,我知道它是std::cout,总是。如果我错了,那就是写这段代码的人的问题,而不是我的问题:)
一切都是为了管理复杂性。使用名称空间将拉入您不想要的东西,因此可能会使调试更加困难(我说可能)。到处使用std::很难阅读(更多的文本和所有这些)。
马的课程-管理你的复杂性如何你能最好地和感觉能力。
您需要能够阅读由与您有不同风格和最佳实践意见的人编写的代码。
如果你只使用cout,没人会感到困惑。但是当有很多名称空间在你周围飞来飞去,你看到这个类,你不确定它到底做了什么,让名称空间显式作为一种注释。您可以第一眼看到,‘哦,这是一个文件系统操作’或者‘这是在做网络工作’。
考虑
1 2 3 4 5 6 7 8 9 10
| // myHeader.h
#include <sstream>
using namespace std;
// someoneElses.cpp/h
#include"myHeader.h"
class stringstream { // uh oh
}; |
注意,这是一个简单的例子,如果您有包含20个include和其他导入的文件,那么您将有大量的依赖项来解决这个问题。更糟糕的是,根据冲突的定义,您可以在其他模块中获得不相关的错误。
这并不可怕,但如果不在头文件或全局命名空间中使用它,就可以省去自己的麻烦。在非常有限的范围内完成这项工作可能没问题,但我从来没有遇到过输入额外的5个字符来说明我的函数来自何处的问题。
同时使用多个名称空间显然是一种灾难,但在我看来,仅使用名称空间std和仅使用名称空间std并不是什么大问题,因为重新定义只能由您自己的代码来发生…
所以只要把它们当作保留名称,比如"int"或"class",就可以了。
人们应该停止对这件事如此无礼。你的老师一直都很好。只需使用一个名称空间;这是首先使用名称空间的全部要点。不能同时使用多个。除非是你自己的。因此,重新定义也不会发生。
- 创建冲突并不是像min、end和less这样的硬短字符串出现在std::名称空间中。但更重要的是,既然std::中有成千上万的符号,读者就可以知道他们可能不知道的新符号来自何处。
- std名称空间的存在是因为人们,无论是您、您的同事,还是编写您使用的中间件的人,并不总是明智地将函数放在名称空间中。因此,您可以导入std::的所有内容,而不导入其他内容,同时仍然调用std::min与其他人在std中之前的遗留::min()之间的冲突。
我同意这里的其他观点,但希望解决有关可读性的问题——您可以通过在文件、函数或类声明的顶部使用typedef来避免所有这些问题。
我通常在类声明中使用它,因为类中的方法倾向于处理类似的数据类型(成员),typedef是分配在类上下文中有意义的名称的机会。这实际上有助于类方法定义的可读性。
1 2 3 4 5 6
| //header
class File
{
typedef std::vector<std::string> Lines;
Lines ReadLines();
} |
在实施过程中:
1 2 3 4 5 6 7
| //cpp
Lines File::ReadLines()
{
Lines lines;
//get them...
return lines;
} |
与之相反:
1 2 3 4 5 6 7
| //cpp
vector<string> File::ReadLines()
{
vector<string> lines;
//get them...
return lines;
} |
或:
1 2 3 4 5 6 7
| //cpp
std::vector<std::string> File::ReadLines()
{
std::vector<std::string> lines;
//get them...
return lines;
} |
- 只是一个小注释,虽然typedef很有用,但我会考虑创建一个表示行的类,而不是使用typedef。
命名空间是命名范围。命名空间用于对相关声明进行分组并保持独立项目分开。例如,两个单独开发的库可以使用相同的名称来引用不同的项,但用户仍然可以同时使用这两个项:
1 2 3 4 5 6 7 8 9 10 11 12 13
| namespace Mylib{
template<class T> class Stack{ /* ... */ };
/ / ...
}
namespace Yourlib{
class Stack{ /* ... */ };
/ / ...
}
void f(int max) {
Mylib: :Stack<int> s1(max) ; / / use my stack
Yourlib: :Stack s2(max) ; / / use your stack
/ / ...
} |
重复命名空间名称可能会分散读者和作者的注意力。因此,这是可能的声明来自特定命名空间的名称在没有显式限定的情况下可用。例如:
1 2 3 4 5 6
| void f(int max) {
using namespace Mylib; / / make names from Mylib accessible
Stack<int> s1(max) ; / / use my stack
Yourlib: :Stack s2(max) ; / / use your stack
/ / ...
} |
名称空间为管理不同库和不同版本的代码。特别是,它们提供了程序员如何明确地引用非本地的姓名。
源代码:C++程序设计语言综述作者:Bjarne Stroustrup
- 非常有趣的是,这个答案是建立在没有其他人的指导下,比亚恩·斯特劳斯鲁普已经赢得了-2…BJARNE,当他把这个特性引入到C++中时,一定是一个贫穷而缺乏经验的程序员。
- @Nyholku:看这个。
澄清问题的具体例子。假设您有两个库,foo和bar,每个库都有自己的名称空间:
1 2 3 4 5 6 7
| namespace foo {
void a(float) { /* does something */ }
}
namespace bar {
...
} |
现在假设您在自己的程序中同时使用foo和bar,如下所示:
1 2 3 4 5 6
| using namespace foo;
using namespace bar;
void main() {
a(42);
} |
在这一点上,一切都很好。当你运行你的程序时,它会"做一些事情"。但后来你更新了这个工具栏,让我们假设它已经改变为:
1 2 3
| namespace bar {
void a(float) { /* does something completely different */ }
} |
此时,您将得到一个编译器错误:
1 2 3 4 5 6
| using namespace foo;
using namespace bar;
void main() {
a(42); // error: call to 'a' is ambiguous, should be foo::a(42)
} |
因此,您需要做一些维护,以澄清您所指的"a"(即foo::a)。这可能是不可取的,但幸运的是,它相当容易(只需在对a的所有调用之前添加foo::,编译器就会将其标记为不明确)。
但是想象一下另一种情况,酒吧变成了这样:
1 2 3
| namespace bar {
void a(int) { /* does something completely different */ }
} |
此时,你对a(42)的调用突然绑定到bar::a而不是foo::a,而不是执行"某个操作",而是执行"完全不同的操作"。没有编译器警告或任何内容。你的程序只是静静地开始做一些与以前完全不同的事情。
当您使用一个名称空间时,您会冒这样的风险,这就是为什么人们不愿意使用名称空间的原因。名称空间中的内容越多,冲突的风险就越大,因此使用名称空间std(由于该名称空间中的内容数量多)的人可能比使用其他名称空间更不舒服。
最终,这是可写性与可靠性/可维护性之间的权衡。可读性也可以考虑,但我可以看到这两种情况的论据。通常我会说可靠性和可维护性更重要,但在这种情况下,您将经常为相当罕见的可靠性/可维护性影响支付可写性成本。"最佳"权衡将决定你的项目和你的优先顺序。
使用名称空间std的一个示例由于计数的模糊性而引发编译错误,这也是算法库中的一个函数。
1 2 3 4 5 6 7 8
| #include <iostream>
using namespace std;
int count = 1;
int main() {
cout<<count<<endl;
} |
- ::count——问题解决了。通常,来自std名称空间的内容比来自其他地方的要多,因此保留using名称空间指令可能会节省您键入的时间。
- 这里真正的问题是C++仍然具有更少的名字空间。这一点,以及"this"在方法中是隐式的这一事实,导致了如此多的错误和问题,即使使用正确的"count"变量,我也无法对它们进行计数。;)
我认为在任何情况下都不一定是不好的做法,但使用时要小心。如果您正在编写一个库,那么您可能应该使用带有名称空间的范围解析操作符来防止您的库与其他库发生冲突。对于应用程序级代码,我看不出它有什么问题。
它不会使您的软件或项目性能变差,在源代码开头包含名称空间也不错。根据您的需求和开发软件或项目的方式,包含using namespace std指令的方式有所不同。
EDCOX1(1)包含C++标准函数和变量。当您经常使用C++标准函数时,这个命名空间很有用。
As is mentioned in this page:
The statement using namespace std is generally considered bad
practice. The alternative to this statement is to specify the
namespace to which the identifier belongs using the scope operator(::)
each time we declare a type.
And see this opinion:
There is no problem using"using namespace std" in your source file
when you make heavy use of the namespace and know for sure that
nothing will collide.
有些人曾说,将using namespace std包含在源文件中是一种糟糕的做法,因为您从该名称空间调用了所有函数和变量。当您想要定义一个与namespace std中包含的另一个函数同名的新函数时,您将重载该函数,它可能由于编译或执行而产生问题。它不会像您期望的那样编译或执行。
As is mentioned in this page:
Although the statement saves us from typing std:: whenever
we wish to access a class or type defined in the std namespace, it
imports the entirety of the std namespace into the current namespace
of the program. Let us take a few examples to understand why this
might not be such a good thing
...
Now at a later stage of development, we wish to use another version of
cout that is custom implemented in some library called"foo" (for
example)
...
Notice how there is an ambiguity, to which library does cout point to?
The compiler may detect this and not compile the program. In the worst
case, the program may still compile but call the wrong function, since
we never specified to which namespace the identifier belonged.
"为什么使用命名空间STD?"被认为是C++中的一个坏习惯吗?
我换一种说法:为什么有些人认为输入5个额外的字符很麻烦?
例如,编写一个数字软件,当"vector"是问题域最重要的概念之一时,为什么还要考虑通过将一般的"std::vector"缩减为"vector"来污染全局命名空间?
- 它不仅仅是5个额外的字符;每次引用标准库中的任何对象类型时,它都是5个额外的字符。如果您经常使用标准库,这将是非常常见的。所以更现实的是,在一个相当大的程序中有数千个额外的字符。可能是"using"指令被添加到了语言中,以便可以使用…
- 它不是每次都有5个额外的字符,而是5个字符,可能需要几次鼠标单击来下拉菜单,并在您选择的编辑器中进行查找和替换。
- 可读性。cout << hex << setw(4) << i << endl;比std::cout << std::hex << std::setw(4) << i << std::endl;更容易阅读。
- 更糟糕的是:与map>相比,std::map>是可怕的。
- 不管怎样,最好的做法是对STL容器进行typedef,所以std::there实际上并不重要。而C++ 11为我们带来了自动关键字,这使得使用迭代器时更容易。
- 同意@juzzlin——目前最好的代码几乎不显示类型。您可以使用"auto"让编译器推断几乎所有的内容。由于推断类型所需的代码通常不存在,因此只有头才有很多要指定的调用。
这取决于它的位置。如果它是一个公共头,那么您将通过将其合并到全局名称空间来减小名称空间的值。记住,这可能是一种使模块全局化的好方法。
对于不合格的导入标识符,您需要像grep这样的外部搜索工具来找出在哪里声明标识符。这使得程序正确性的推理变得更加困难。
我同意其他人的看法——这是在要求名字冲突,模棱两可,然后事实是它不那么明确。虽然我可以看到using的使用,但我个人的偏好是限制它。我也会强烈考虑其他人指出的:好的。
如果您想找到一个可能是一个相当常见的名称的函数名,但只想在std名称空间中找到它(或者反过来,您想更改不在名称空间std中、名称空间X中的所有调用),那么您打算如何做呢?你可以写一个程序来完成它,但是花时间在你的项目本身上,而不是写一个程序来维护你的项目,难道不是更好吗?好的。
就我个人而言,我并不介意std::前缀。我更喜欢它的外观而不是没有它。我不知道这是不是因为它是明确的并且对我说"这不是我的代码…我正在使用标准库"或者如果它是其他东西,但我认为它看起来更好。这可能是奇怪的,因为我最近才进入C++(使用和仍然做C和其他语言更长的时间,C是我最喜欢的语言的所有时间,就在大会)。好的。
还有另外一件事,尽管它与上述以及其他人指出的有些关系。虽然这可能是不好的做法,但我有时会将std::name保留为标准库版本,并为特定于程序的实现保留名称。是的,这确实会咬你,咬你一口,但归根结底,我从零开始这个项目,我是唯一的程序员。示例:我重载std::string,并将其称为string。我有一些有用的补充。我之所以这样做,部分是因为我的C和Unix(+Linux)倾向于使用小写名称。好的。
除此之外,还可以有名称空间别名。下面是一个例子,说明它在哪些地方有用,而这些地方可能没有被提及。我使用C++ 11标准,特别是用LIbSTDC++ ++。嗯,它没有完整的std::regex支持。当然,它会编译,但它会抛出一个异常,这是程序员端的一个错误。但它缺乏实施。我就是这样解决的。安装Boost的Regex,连接它。然后,我执行以下操作,以便当libstdc++完全实现它时,我只需要删除这个块,代码保持不变:好的。
1 2 3 4 5 6 7 8 9 10
| 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(但这是一个很好的练习,也是一个让自己成为A、学习另一种语言和B的好方法。尽量不要对对象/类等有太大的偏见,这可能更好地说是不那么封闭、不那么傲慢、更容易接受)。但有用的是一些人已经建议的:我确实使用列表(它是相当通用的,不是吗?)(同样的事情)把两个名字分类,如果我做using namespace std;的话,会引起名字冲突,为此,我更喜欢具体化、控制和知道如果我打算把它作为标准用途,那么我必须指定它。简而言之:不允许假设。好的。
至于让Boost的regex成为std的一部分。我这样做是为了将来的整合,而且——再次,我完全承认这是一种偏见——我认为这并不像boost::regex:: ...那样丑陋——事实上,这对我来说是另一回事。在C++中有很多东西我还没有完全在外观和方法中接受(另一个例子:可变模板与var ARGs)[虽然我承认可变模板是非常有用的!)即使是我接受的那些人也很困难,我仍然和他们有问题。好的。好啊。
- 扩展std名称空间是未定义的行为,因此不应该这样做。
这是一种不好的做法,通常被称为全球名称空间污染。当多个命名空间具有相同的带签名的函数名时,可能会出现问题,那么编译器将无法确定要调用哪个命名空间,而当您使用类似std::cout的函数调用指定命名空间时,可以避免这一切。希望这有帮助。:)
根据我的经验,如果您有多个库,比如说,cout,但出于不同的目的,您可能会使用错误的cout。
例如,如果我输入,using namespace std;和using namespace otherlib;和type只是不能(恰好两者都有),而不是std::cout或'otherlib::cout'的类型,你可能会使用错误的类型,并得到错误,那么使用std::cout更有效。
为了回答你的问题,我实际上是这样看的:很多程序员(不是所有人)都调用名称空间std。因此,人们应该养成不使用与名称空间std中名称相同的东西的习惯。这是非常理所当然的,但与可能的连贯单词和假名的数量相比,这是不太可能的。这可以严格地说出来。
我是说真的…说"不要依赖这个存在",就是让你相信它不存在。您经常会遇到借用代码片段并不断修复它们的问题。只要保持你的用户定义和借来的东西在有限的范围内,因为他们应该,并非常节省与全球(老实说,全球应该几乎总是最后的手段,目的是"编译现在,健全以后")。我真的认为这是老师的坏建议,因为使用std对"cout"和"std::cout"都有效,但不使用std只对"std::cout"有效。您并不总是幸运地编写自己的代码。
注意:在您真正了解编译器的工作原理之前,不要过于关注效率问题。有了一点编码的经验,在你意识到好的代码能够概括为简单的东西之前,你不必对它们了解那么多。每一点都很简单,就好像你用C语言写了整件事一样。好的代码只是它需要的那么复杂而已。
- 考虑到有多少人似乎不知道有用的标准库功能(例如,从中重新发明东西),想象同一个人能够可靠地避免这些标识符似乎有点夸张。查看您自己的代码,告诉我您从来没有名为count的变量或函数。1、3、EDCOX1、4、EDCOX1、5、EDCX1、6、EDCX1、8、EDCX1、9、EDCX1、11、EDCX1、12、EDCX1、13、EDCX1、On等,更不用说EDCOX1ω中的所有标识符,当C++出现时会破坏代码。或distance,或EDOCX
是的,命名空间很重要。在我的项目中,我需要将一个var声明导入到我的源代码中,但是在编译它时,它与另一个第三方库冲突。
最后,我不得不用其他方法来绕过它,使代码不那么清晰。
我认为本地或全局使用应该取决于应用程序。
因为,当我们在本地使用库时,有时代码会变得一团糟。可读性将下降。
因此,只有在可能发生冲突的情况下,我们才应该在本地使用库。
我不是经验丰富的人。所以,如果我错了就告诉我。
下面是一个示例,说明using namespace std;如何导致名称冲突问题:
无法在C++中定义全局变量
在示例中,非常通用的算法名称(std::count名称)与非常合理的变量名称(count名称)冲突。
老实说,对我来说,这就像讨论缩进的空格数。在头中使用指令会造成损坏。但是在C++文件中呢?如果您同时使用两个名称空间,可能是这样。但如果你使用一个,它更多的是关于风格而不是真正的效率。你知道为什么关于缩进的线程如此流行吗?任何人都可以说点什么,听起来很聪明,很有经验。
这里有一个观点,我在其他任何答案中都没有找到:只使用一个名称空间。根据大多数答案,名称空间不好的主要原因是,您可能有相互冲突的函数名,这可能导致完全混乱。但是,如果只使用一个名称空间,则不会发生这种情况。决定使用最多的库(可能是using namespace std;)并坚持使用。
可以认为它有一个不可见的库前缀——std::vector变成了vector。在我看来,这是两个领域中最好的一个:一方面它减少了您必须执行的输入量(如名称空间所预期的那样),另一方面,它仍然要求您使用前缀以提高清晰度和安全性。如果有一个没有名称空间前缀的函数或对象,您知道它来自您声明的名称空间。
记住,如果你决定在全球范围内使用一个-不要在本地使用其他的。这又回到了另一个答案,即本地名称空间通常比全局名称空间更有用,因为它们提供了各种方便。