使用std命名空间
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用std命名空间相关的知识,希望对你有一定的参考价值。
关于std命名空间使用'using'似乎有不同的看法。
有人说使用'using namespace std
',其他人说不要,而是使用与'std::
'一起使用的前缀std函数,而其他人则说使用这样的东西:
using std::string;
using std::cout;
using std::cin;
using std::endl;
using std::vector;
对于要使用的所有std函数。
各自的优点和缺点是什么?
大多数C ++用户都非常高兴阅读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
进入全局命名空间并且函数计数隐藏它。
#include <algorithm>
using namespace std;
int increment()
{
static int count = 0;
return ++count;
}
也许有点令人惊讶,这是可以的。导入到声明性作用域中的标识符出现在公共名称空间中,该名称空间包含它们的定义位置和导入位置。换句话说,std::count
在全局命名空间中显示为count
,但仅在increment
中。
#include <algorithm>
int increment()
{
using namespace std;
static int count = 0;
return ++count;
}
由于类似的原因,count
在这里含糊不清。 using namespace std
不会导致std::count
,隐藏外部count
,因为它可能是预期的。 using namespace
规则意味着std::count
看起来(在increment
函数中)好像它是在全球范围内宣布的,即与int count = 0;
在相同的范围内,因此导致模糊性。
#include <algorithm>
int count = 0;
int increment()
{
using namespace std;
return ++count; // error ambiguous
}
命名空间保留代码以防止函数签名的confusion和pollution。
Here是proper namespace用法的完整文档演示:
#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();
}
输出:
Our log: 42
Standard log: 1.43508
就像在Java中你可以使用的那样,可以包括java.util。*或者只是单独选择每个类,它取决于样式。请注意,您不希望在文件/宽范围的开头有一个using namespace std
,因为您将污染命名空间并可能发生冲突,从而破坏了命名空间点。但是如果你有一个使用大量STL的函数,它会使代码混乱,在你的逻辑中混杂使用前缀语法,你应该考虑使用using namespace std
(当使用各种类时)或单独的using
s(当使用时经常很少上课)。
只要您使用的IDE不够灵活,无法显示或隐藏您需要的确切信息,此讨论将继续存在。
这是因为您希望代码看起来像是取决于手头的任务。
在创建我的源代码时,我更喜欢看到我正在使用哪个类:是std::string
还是BuzFlox::Obs::string
类?
在设计控制流时,我甚至不对变量的类型感兴趣,但我想关注if
和while
和continue
。
所以这是我的建议:
根据您的代码的受众和工具的强大功能,选择最简单的方式或提供大多数信息的方式。
有几种方法可以解决这个问题。
第一:像你所做的一样使用。
第二:做namespace S = std;
,减少2个字符。
第三:使用static
。
第四:不要使用std
使用的名称。
每种方法的优缺点是什么?
离开std ::的唯一原因是,理论上你可以自己重新实现所有的STL函数。然后你的函数可以从使用std :: vector切换到my :: vector而无需更改代码。
举个例子
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>&);
返回值是哪一个?
相反怎么样
typedef std::vector<unsigned int> values_t;
typedef std::vector<unsigned int> histogram_t;
...
void getHistogram(values_t&, histogram_t&);
排除基础知识(必须添加所有stl对象/函数的std :: infront,如果没有'using namespace std',则冲突的可能性更小)
值得注意的是,你永远不应该放
using namespace std
在头文件中,因为它可以传播到包含该头文件的所有文件,即使他们不想使用该命名空间。
在某些情况下,使用像这样的东西是非常有益的
using std::swap
好像有一个专门的swap版本,编译器将使用它,否则它将回退到std :: swap
如果调用std :: swap,则始终使用基本版本,该版本不会调用优化版本(如果存在)。
首先,一些术语:
- 使用声明:
using std::vector;
- using-directive:
using namespace std;
我认为使用using-directives是好的,只要它们不在头文件的全局范围内使用。所以有
using namespace std;
在你的.cpp文件中并不是一个真正的问题,如果事实证明,它完全在你的控制之下(如果需要它甚至可以限定为特定的块)。我没有看到任何特别的理由用一大堆std::
限定符来混淆代码 - 它只是变成了一堆视觉噪音。但是,如果您没有在代码中使用std
命名空间中的一大堆名称,我也发现删除该指令没有问题。这是一个重言式 - 如果指令不是必要的,那么就没有必要使用它了。
类似地,如果你可以在std
命名空间中使用一些using声明(而不是using-directives)来获取特定类型,那么你就没有理由不应该只将那些特定的名称带入当前的命名空间。出于同样的原因,我认为当一个使用指令也可以做到这一点时,拥有25或30个使用声明会是疯狂和簿记的麻烦。
记住有时你必须使用using声明也是很好的。请参阅Scott Meyers的“第25版:考虑支持非投掷互换”,来自Effective C ++,Third Edition。为了使通用的模板化函数对参数化类型使用“最佳”交换方法,您需要使用using声明和参数依赖查找(也称为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 ++更多)。在这些语言中使用名称空间中最常见的方式名称是将它们集中到当前作用域中,使用等效的using-directive。这不会导致广泛传播的问题,并且通过完全限定名称或别名来处理有问题的名称,就可以在“异常”的基础上处理问题的几次 - 就像在C ++中完成一样。
Herb Sutter和Andrei Alexandrescu在“项目59:不在头文件中或在#include之前编写命名空间”这一点中说明了他们的书,C ++编码标准:101规则,指南和最佳实践:
简而言之:在
#include
指令之后,你可以而且应该在你的实现文件中使用声明和指令使用命名空间,并且感觉良好。尽管反复断言,使用声明和指令的命名空间并不是邪恶的,并且它们不会破坏命名空间的目的。相反,它们是命名空间可用的原因。
Stroupstrup经常被引用为“不要污染全局命名空间”,在“The C ++ Programming Language,Third Edition”中。事实上,他确实说过(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()
的歧义错误。全局名称不会优先于全局范围内可访问的名称空间中的名称。这为意外名称冲突提供了重要保护,并且 - 重要的是 - 确保从污染全局命名空间中获得的任何优势都没有。当通过using-directives使可以访问声明许多名称的
以上是关于使用std命名空间的主要内容,如果未能解决你的问题,请参考以下文章
linux eclipse c++ 本地命名空间和“std::”
使用命名空间的区别(std:: vs ::std::)[重复]