在使用与std命名空间相关的“using”时,似乎存在不同的观点。
有人说要使用“using namespace std
”,而另一些人则说不要这样做,而是要在使用的std函数前加上“std::
”前缀,还有一些人建议使用类似于以下内容:
using std::string;
using std::cout;
using std::cin;
using std::endl;
using std::vector;
对于所有要使用的标准函数,它们各自有哪些优缺点?
在使用与std命名空间相关的“using”时,似乎存在不同的观点。
有人说要使用“using namespace std
”,而另一些人则说不要这样做,而是要在使用的std函数前加上“std::
”前缀,还有一些人建议使用类似于以下内容:
using std::string;
using std::cout;
using std::cin;
using std::endl;
using std::vector;
对于所有要使用的标准函数,它们各自有哪些优缺点?
std::string
, std::vector
等标准库容器。事实上,看到一个裸露的vector
让我想知道这是std::vector
还是不同的用户定义vector
。using namespace std;
。它会将各种名称导入全局命名空间,并可能导致各种不明显的歧义。std
命名空间中的标识符:count、sort、find、equal、reverse。如果有一个叫做count
的局部变量,那么使用using namespace std
就无法使用count
代替std::count
。std::count
。想象一下,您正在使用<algorithm>
中的其他东西,或者它已经被一个看似不相关的头文件引入。#include <algorithm>
using namespace std;
int count = 0;
int increment()
{
return ++count; // error, identifier count is ambiguous
}
错误通常很长且不友好,因为std::count
是一个带有一些嵌套类型的模板。
尽管如此,这没关系,因为std::count
进入全局命名空间,并且函数count将其隐藏起来。
#include <algorithm>
using namespace std;
int increment()
{
static int count = 0;
return ++count;
}
或许有些令人惊讶,但这是可以的。导入到声明作用域中的标识符会出现在公共命名空间中,该命名空间包含定义它们和导入它们的位置。换句话说,std::count
在全局命名空间中可见,但仅在 increment
内部可见作为 count
。#include <algorithm>
int increment()
{
using namespace std;
static int count = 0;
return ++count;
}
出于类似的原因,count
在此处是有歧义的。使用 using namespace std
并不会将 std::count
隐藏起来,像预期的那样隐藏外部的 count
。 using namespace
规则意味着在 increment
函数中,std::count
看起来就像是在全局作用域声明的,也就是和 int count = 0;
相同的作用域位置,从而导致了歧义。
#include <algorithm>
int count = 0;
int increment()
{
using namespace std;
return ++count; // error ambiguous
}
int swap; using namespace std; int main() { ::swap = 1; }
,它始终是非歧义的:显式指定作用域将搜索使用指令放置的命名空间 - 但它永远不会与现有声明发生冲突。这只会在未经限定的名称查找时发生。 - Johannes Schaub - litb除了基础知识(需要在所有STL对象/函数前面添加std::并且如果不使用'using namespace std'则冲突的可能性较小)
还值得注意的是,您永远不应该放置
using namespace std
在头文件中使用命名空间可能会传播到包含该头文件的所有文件,即使它们不想使用该命名空间也是如此。
在某些情况下,使用诸如
using std::swap
如果有一个专用版本的swap,编译器将使用该版本,否则它将回退到std::swap
。
如果调用std::swap
,你总是使用基本版本,它不会调用优化版本(如果存在)。
swap
或move
(或hash
,less
等)专业化,则应将该专业化放入namespace std
中。例如:namespace std {template<> class hash<X> {public: size_t operator()(const X&) const};} class X: {friend size_t std::hash<X>::operator()(const X&)};
- AJMansfieldswap
重载放入std
命名空间是不推荐的,请参考https://stackoverflow.com/questions/14402990/should-you-overload-swap-in-the-std-namespace。 - undefined首先,一些术语:
using std::vector;
(使用声明)using namespace std;
(使用指令)我认为使用使用指令是可以的,只要它们不在头文件的全局范围内使用。因此,有
using namespace std;
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>()
// ...
}
通过使用 using-directive,您可以像“懒惰地使用全局名称”的用户一样获得相同的优势,并且可以安全地将命名空间中的名称提供给当前范围。请注意,有一个区别 - 通过正确使用 using-directive(将指令放置在 #includes 后面),使得 std 命名空间中的名称可用于作用域时,不会污染全局命名空间。它仅仅是方便地使这些名称可用,并继续保护免受冲突的影响。A using-declaration adds a name to a local scope. A using-directive does not; it simply renders names accessible in the scope in which they were declared. For example:
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 }
A locally declared name (declared either by an ordinary declaration or by a using-declaration) hides nonlocal declarations of the same name, and any illegal overloadings of the name are detected at the point of declaration.
Note the ambiguity error for
k++
inf1()
. Global names are not given preference over names from namespaces made accessible in the global scope. This provides significant protection against accidental name clashes, and – importantly – ensures that there are no advantages to be gained from polluting the global namespace.When libraries declaring many names are made accessible through using-directives, it is a significant advantage that clashes of unused names are not considered errors.
...
I hope to see a radical decrease in the use of global names in new programs using namespaces compared to traditional C and C++ programs. The rules for namespaces were specifically crafted to give no advantages to a ‘‘lazy’’ user of global names over someone who takes care not to pollute the global scope.
std::
限定符不会混杂在代码中 — 还有其他方法来避免这种情况(通常使用声明或类型定义就可以了)。 - Michael Burrstd::list
。 这与没有“using namespace std;”指令没有什么区别。或者我错过了什么? - Michael Burrtypedef 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”。测试通过了。“module”没有以影响其ABI的方式进行修改,因此“engine”库可以在不重新编译其用户的情况下使用。集成测试也是OK的。新的“module”发布了。当引擎的代码没有被修改时,下一次编译就会失败。
using namespace std;
但如果您想准确了解文档中代码的依赖关系,或者存在名称冲突的风险,请使用另一种方式:
using std::string;
using std::cout;
两者都
using std::string;
并且
using namespace std;
在全局命名空间中添加一些符号(一个或多个)。在头文件中添加符号到全局命名空间是不应该做的事情。你无法控制谁会包含你的头文件,有很多头文件包含其他头文件(和包含其他头文件的头文件等等...)。
在实现(.cpp)文件中,这取决于你(只需记住在所有#include指令之后执行)。你只能破坏这个特定文件中的代码,所以更容易管理和找出名称冲突的原因。如果你喜欢在标识符之前使用std::(或任何其他前缀,在你的项目中可能有许多命名空间),那么没问题。如果你想要将你使用的标识符添加到全局命名空间中,也可以。如果你想把整个命名空间都带在头上 :-),那就由你了。虽然影响仅限于单个编译单元,但是它是可以接受的。
对我来说,我更喜欢在可能的情况下使用::
。
std::list<int> iList;
我讨厌写作:
for(std::list<int>::iterator i = iList.begin(); i != iList.end(); i++)
{
//
}
for(auto i = iList.begin(); i != iList.end(); i++)
{
//
}
namespace dir = boost::filesystem;
dir::directory_iterator file("e:/boost");
dir::directory_iterator end;
for( ; file != end; file++)
{
if(dir::is_directory(*file))
std::cout << *file << std::endl;
}
++i
иҖҢдёҚжҳҜi++
жқҘйҖ’еўһпјҢеӣ дёәеҰӮжһңе®ғиў«е®ҡд№үпјҢдјҡеҲӣе»әдёҖдёӘдёҚеҝ…иҰҒзҡ„дёҙж—¶еүҜжң¬гҖӮ - Felix Dombek#include <iostream>
#include <cmath> // Uses ::log, which would be the log() here if it were not in a namespace, see https://dev59.com/Kmct5IYBdhLWcg3wsPd5
// 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();
}
输出:
Our log: 42
Standard log: 1.43508
using namespace std
。此外,我认为大多数程序员看到没有std::
的vector
或string
时会感到困惑,因此我认为最好不要使用using namespace std
。因此,我主张完全不使用using namespace std
。using std::vector
。但是请问自己:这值得吗?一行代码只写一次(也许两次),但是它被阅读了十次、百次甚至千次。与阅读代码的努力相比,添加using声明或指令所节省的输入工作微不足道。using
的人通常还没有尝试过用于一个项目。而那些尝试过的人往往在很短的时间内发现它比using指令/声明更好。using std::swap
,这是必要的(特别是在通用代码中),以选择无法放入std
命名空间的swap()
重载(因为我们不允许将std
函数的重载放入此命名空间)。using namespace
指令的意图并不是为了使打字更容易;相反,它是为了使阅读更容易,因为正如你所说,那段代码将被阅读数十次、数百次甚至数千次。对于一些人来说,少一些std::
的干扰会让代码更容易阅读。但这可能取决于个人的感知能力;有些人会过滤掉std::
或者需要它作为指引(就像衬线字体),而另一些人则会在其上跌跌撞撞,感觉像在崎岖的道路上行驶。 - Lumiusing namespace std
导入了当前命名空间中的 std
命名空间的内容。因此,优点是您不必在该命名空间的所有函数前面键入 std::
。但是,可能会出现您有不同的命名空间具有相同名称的函数的情况。因此,您可能最终没有调用您想要的那个。
手动指定要导入到 std
中的函数可以防止发生这种情况,但可能会导致文件开头出现很长的使用列表,这可能会让一些开发人员感到丑陋 ;)!
个人而言,我更喜欢每次使用函数时都指定命名空间,除非命名空间太长,在这种情况下,我会在文件开头放置一些使用语句。
编辑:如另一个答案中所述,您永远不应在头文件中放置 using namespace
,因为它将传播到包括此头文件的所有文件中,从而可能产生不希望的行为。
编辑2:根据 Charles 的评论纠正了我的答案。
using namespace std;
将 std
命名空间的内容导入全局命名空间。它不会改变默认命名空间。在 using namespace std
之后在全局命名空间中定义某些内容并不能自动将其放入 std
命名空间中。 - CB Bailey