我听说 using namespace std;
是不好的做法,我应该直接使用 std::cout
和 std::cin
。为什么是这样?是否冒着声明与 std
命名空间中的某些东西同名的变量的风险?
std::literals::chrono_literals
、Poco::Data:Keywords
、Poco::Units
和处理文字或可读性技巧的东西。每当它在头文件或实现文件中时。我猜在函数范围内可能没问题,但除了文字和其他东西之外,它没有用。
考虑两个名为 Foo 和 Bar 的库:
using namespace foo;
using namespace bar;
一切正常,您可以毫无问题地从 Foo 调用 Blah()
和从 Bar 调用 Quux()
。但是有一天您升级到 Foo 2.0 的新版本,它现在提供了一个名为 Quux()
的函数。现在您遇到了冲突:Foo 2.0 和 Bar 都将 Quux()
导入您的全局命名空间。这将需要一些努力来解决,特别是如果函数参数恰好匹配。
如果您使用了 foo::Blah()
和 bar::Quux()
,那么 foo::Quux()
的引入就不会发生。
情况可能会变得更糟,比Greg wrote更糟!
Library Foo 2.0 可以引入一个函数 Quux()
,它对于您对 Quux()
的某些调用而言无疑比您的代码多年来调用的 bar::Quux()
更匹配。然后你的代码仍然可以编译,但是它默默地调用了错误的函数并且天知道了。这几乎是最糟糕的事情了。
请记住,std
命名空间有大量标识符,其中许多是非常 常见的(想想 list
、sort
、string
、iterator
等),它们也很可能出现在其他代码中。
如果您认为这不太可能:在我给出这个答案大约半年后,Stack Overflow 上的 a question asked 几乎完全发生了这种情况(由于省略了 std::
前缀而调用了错误的函数)。 Here 是此类问题的另一个较新的示例。所以这是一个真正的问题。
这里还有一个数据点:很多很多年前,我也曾经发现必须在标准库的所有内容前加上 std::
前缀很烦人。然后我在一个项目中工作,一开始就决定除了函数范围外,using
指令和声明都被禁止。你猜怎么着?我们大多数人花了几个星期来习惯编写前缀,再过几个星期,我们大多数人甚至同意它实际上使代码更具可读性。这是有原因的:你喜欢更短还是更长的散文是主观的,但前缀客观地增加了代码的清晰度。不仅是编译器,你也是,发现更容易查看引用了哪个标识符。
十年后,该项目发展到拥有数百万行代码。由于这些讨论一次又一次地出现,我曾经很好奇(允许的)函数范围 using
在项目中实际使用的频率。我搜索了它的来源,只找到了一两打使用它的地方。对我来说,这表明,一旦尝试,即使在允许使用的地方,即使每 100 kLoC 使用一次,开发人员也不会觉得 std::
痛苦到足以使用 using 指令。
底线:明确地为所有内容添加前缀不会造成任何伤害,几乎不需要习惯,并且具有客观优势。特别是,它使编译器和人类读者更容易解释代码——这可能是编写代码时的主要目标。
foo
而不是 Foo
?静态方法也应该称为 Foo::Bar
而不是 Foo::bar
。这就是为什么人们认为约定是一件好事。
foo::bar
作为静态方法仍然不是反对解释点的论据。该函数/方法所属的位置仍然更清楚,如果您给您的类起一个好名字,那么仍然很清楚是一个类而不是命名空间。
将 using namespace
放在类的头文件中的问题在于,它会强制任何想要使用您的类(通过包含您的头文件)的人也“使用”(即查看所有内容)其他名称空间。
但是,您可以随意在您的(私有)*.cpp 文件中添加 using 语句。
请注意,有些人不同意我这样说“随意”——因为尽管 cpp 文件中的 using
语句比标题中的更好(因为它不会影响包含你的头文件),他们认为它仍然不是好(因为根据代码,它可能会使类的实现更难维护)。 This C++ Super-FAQ entry 说,
using 指令适用于遗留 C++ 代码并简化向命名空间的转换,但您可能不应该定期使用它,至少不要在新的 C++ 代码中使用它。
常见问题解答提出了两种选择:
使用声明: using std::cout; // using-declaration 允许您使用 cout 没有限定 cout << "Values:";
只需输入 std:: std::cout << "Values:";
我最近遇到了关于 Visual Studio 2010 的投诉。事实证明,几乎所有的源文件都有这两行:
using namespace std;
using namespace boost;
很多 Boost 功能正在进入 C++0x 标准,而 Visual Studio 2010 有很多 C++0x 功能,所以突然这些程序无法编译。
因此,避免 using namespace X;
是一种面向未来的形式,一种确保对正在使用的库和/或头文件的更改不会破坏程序的方法。
using
,也很少使用 using namespace
。
短版:不要在头文件中使用全局 using
声明或指令。随意在实现文件中使用它们。以下是 Herb Sutter 和 Andrei Alexandrescu 在 C++ Coding Standards 中对这个问题的看法(粗体表示强调是我的):
总结 命名空间使用是为了您的方便,而不是让您强加于他人:切勿在#include 指令之前编写 using 声明或 using 指令。推论:在头文件中,不要写命名空间级别的 using 指令或 using 声明;相反,明确命名空间限定所有名称。 (第二条规则从第一条开始,因为标头永远无法知道其他标头#includes 可能出现在它们之后。) 讨论简而言之:您可以并且应该在#include 指令之后的实现文件中自由地使用命名空间使用声明和指令,并且感觉很好。尽管反复断言相反,使用声明和指令的命名空间并不是邪恶的,它们不会破坏命名空间的目的。相反,它们使命名空间可用。
using
一词不应出现在标题中的说法,但我并不相信将 using namespace xyz;
放置在代码中任何位置的免费许可,尤其是如果 xyz
是 std
。我使用 using std::vector;
形式,因为它只会将命名空间中的单个元素拉入伪全局范围,因此导致冲突的风险要小得多。
using namespace
是邪恶的,就像goto
是邪恶的一样。两者都有有效的用途,但 1000 次中有 999 次会被错误地使用。所以,是的,在源代码中使用 using namespace
您不会污染其他包含的命名空间,整洁。但它仍然不能保护您免受 using namespace Foo
+ using namespace Bar
引起的 "fun" 与您调用 (implicit Foo::) baz(xyz)
并突然代码中断(没有相关更改)只是因为 Bar::baz()
被添加到某处,恰好是一个更好的匹配(因此现在被调用)
不应在全局范围内使用 using
指令,尤其是在标头中。但是,在某些情况下,即使在头文件中也是合适的:
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
...)要好,因为它更短并且能够处理用户定义的浮点类型(通过 argument-dependent lookup (ADL))。
using std::cos;
、 using std::sin
等。但问题是任何设计良好的 userlib
都将在其自己的命名空间中拥有它们的 sin
和 cos
,因此这对您确实没有帮助。 (除非在这个模板之前有一个 using namespace userlib
并且它和 using namespace std
一样糟糕 - 并且范围没有限制。)此外,我见过的唯一这样的函数是 swap
,并且在在这种情况下,我建议只创建 std::swap
的模板特化并避免整个问题。
template<typename T> void swap(MyContainer<T>&, MyContainer<T>&)
(没有函数模板部分专业化(FTPS),所以有时您需要求助于重载。
x
有一个或多个“关联命名空间”(例如,如果它在 namespace userlib
中定义),那么任何看起来像 cos(x)
的函数调用都会另外查看这些命名空间—— 无需事先任何using namespace userlib;
。 Zan Lynx 是对的(C++ 名称查找是拜占庭式的......)
using namespace std;
,我更喜欢 using std::sin; using std::cos; using std::exp;
。您可以获得相同的好处,而没有将 std::*
倾倒到函数中的任何风险。
不要全局使用
只有在全局使用时才被认为是“坏的”。因为:
你把你正在编程的命名空间弄得乱七八糟。
当您使用许多 using namespace xyz; 时,读者将很难看到特定标识符的来源。
对于你的源代码的其他读者来说是正确的,对于它最常见的读者来说更是如此:你自己。一两年后回来看看...
如果你只谈论 using namespace std;您可能不知道您抓取的所有内容 - 当您添加另一个 #include 或移动到新的 C++ 修订版时,您可能会遇到您不知道的名称冲突。
您可以在本地使用它
继续并在本地(几乎)自由使用它。当然,这会阻止您重复 std::
- 而且重复也很糟糕。
在本地使用它的成语
在 C++03 中有一个习惯用法 -- 样板代码 -- 用于为您的类实现 swap
函数。建议您实际使用本地 using namespace std;
- 或至少 using std::swap;
:
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
的实现以找到潜在的重载并选择它。
swap
确实不再那么重要,因为 std::swap
本身更灵活(使用移动语义)。但是 std::swap
会自动选择您自己的自定义交换,这对我来说绝对是新事物(而且我不太相信)。
using std::swap;
而不是 using namespace std;
。更具体的习语具有更少的副作用,因此使代码更易于维护。
swap
的正确方式,并且标准中的许多其他地方都被更改为这样调用 swap
(注意为如上所述,using std::swap
是正确的方式,而不是 using namespace std
)。但是 std::swap
本身被强调没有更改为找到其他一些 swap
并使用它。如果调用 std::swap
,则使用 std::swap
。
using std::swap
可能更明智,以减少本地命名空间,同时创建自记录代码。您很少对整个 std 命名空间感兴趣,因此只需挑选出您感兴趣的部分。
如果您导入正确的头文件,您的全局范围内会突然出现 hex
、left
、plus
或 count
之类的名称。如果您不知道 std::
包含这些名称,这可能会令人惊讶。如果您还尝试在本地使用这些名称,可能会导致一些混乱。
如果所有标准的东西都在它自己的命名空间中,那么您不必担心与您的代码或其他库的名称冲突。
distance
了。在实际可行的情况下,我仍然更喜欢非限定名称,因为这增加了我的可读性。另外,我认为我们通常不会在口头演讲中对事物进行限定,并且愿意花时间解决可能的歧义,这意味着能够理解一个人在没有限定条件的情况下谈论的内容是有价值的,并将其应用于源代码意味着它的结构使得即使没有资格也很清楚它的全部内容。
<iomanip>
,您就不会有其中的大部分。不过,好点。
<iomanip>
来获取带有参数的操纵器,例如 setw
。
另一个原因是惊喜。
如果我看到 cout << blah
,而不是 std::cout << blah
,我会想:这是什么 cout
?是正常的cout
吗?有什么特别的吗?
cout
是一个不好的例子,因为每个人都承认它。但想象一下金融应用程序中的 future
。是否是在指定日期买卖某物的合同?不,不是。如果代码是 std::future
,你就不会那么容易混淆了。
有经验的程序员使用任何可以解决他们的问题的方法并避免任何产生新问题的方法,并且出于这个确切原因,他们会避免使用头文件级别的使用指令。
有经验的程序员也尽量避免在其源文件中完全限定名称。造成这种情况的一个次要原因是,除非有充分的理由,否则在更少的代码就足够的情况下编写更多的代码并不优雅。造成这种情况的一个主要原因是关闭参数相关查找 (ADL)。
这些好的理由是什么?有时程序员明确想要关闭 ADL,有时他们想要消除歧义。
所以以下是可以的:
函数实现中的函数级 using-directives 和 using-declarations 源文件中的源文件级 using-declarations(有时) 源文件级 using-directives
我同意它不应该在全球范围内使用,但在本地使用它并不是那么邪恶,就像在 namespace
中一样。以下是 “C++ 编程语言” 中的一个示例:
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;
高十行。或该文件中名为 cout
的 static
变量。它可以是任何东西。
现在拿一百万行代码库,它不是特别大,并且您正在寻找一个错误,这意味着您知道这百万行中有一行没有完成它应该做的事情。 cout << 1;
可以读取名为 cout
的 static int
,将其向左移动一位,然后丢弃结果。寻找错误,我必须检查。你能看出我真的很喜欢看std::cout
吗?
如果您是一名教师,并且从来不需要编写和维护任何代码为生,那么这似乎是一个非常好的主意。我喜欢在哪里看到代码(1)我知道它做了什么;并且,(2)我相信写它的人知道它的作用。
这一切都与管理复杂性有关。使用命名空间会拉入你不想要的东西,因此可能会使调试变得更加困难(我说可能)。到处使用 std:: 更难阅读(更多文本等等)。
课程用马 - 以您最好的方式和感觉能力管理您的复杂性。
考虑
// myHeader.h
#include <sstream>
using namespace std;
// someoneElses.cpp/h
#include "myHeader.h"
class stringstream { // Uh oh
};
请注意,这是一个简单的示例。如果您有包含 20 个包含和其他导入的文件,那么您将需要通过大量依赖项来解决问题。更糟糕的是,根据冲突的定义,您可能会在其他模块中出现不相关的错误。
这并不可怕,但您可以通过不在头文件或全局命名空间中使用它来避免头疼。在非常有限的范围内这样做可能没问题,但我从来没有遇到过输入额外的五个字符来阐明我的函数来自哪里的问题。
using namespace std
仅存在于实现文件中怎么办?
一个具体的例子来澄清这个问题。假设您有两个库 foo
和 bar
,每个库都有自己的命名空间:
namespace foo {
void a(float) { /* Does something */ }
}
namespace bar {
...
}
现在假设您在自己的程序中同时使用 foo
和 bar
,如下所示:
using namespace foo;
using namespace bar;
void main() {
a(42);
}
此时一切都很好。当您运行程序时,它会“做某事”。但是稍后您更新 bar
并假设它已更改为:
namespace bar {
void a(float) { /* Does something completely different */ }
}
此时你会得到一个编译器错误:
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::
)。
但是想象一下另一种情况,其中 bar 改为如下所示:
namespace bar {
void a(int) { /* Does something completely different */ }
}
此时,您对 a(42)
的调用突然绑定到 bar::a
而不是 foo::a
,而不是执行“某事”,而是执行“完全不同的事”。没有编译器警告或任何东西。您的程序只是默默地开始做一些与以前完全不同的事情。
当您使用命名空间时,您会面临这样的情况,这就是人们不喜欢使用命名空间的原因。命名空间中的事物越多,冲突的风险就越大,因此人们可能会比使用命名空间 std
(由于该命名空间中的事物数量)比其他命名空间更不舒服。
最终,这是可写性与可靠性/可维护性之间的权衡。可读性也可能是一个因素,但我可以看到这两种方式的论点。通常我会说可靠性和可维护性更重要,但在这种情况下,您将不断为相当罕见的可靠性/可维护性影响支付可写成本。 “最佳”权衡将决定您的项目和优先事项。
using
指令指定它应该引入使用旧版本号标记的成员,而不是那些被标记的成员与较新的。如果在程序员编写 using
指令时,库的最新版本是 147,则程序在 using 指令中包含该版本号,并且以后添加的任何函数都用更高的数字标记,代码指定版本 147 将继续以与以往相同的方式工作。
您需要能够阅读与您有不同风格和最佳实践意见的人编写的代码。如果你只使用 cout,没有人会感到困惑。但是,当您有很多名称空间飞来飞去并且您看到这个类并且您不确定它的作用时,让名称空间显式充当某种注释。乍一看,“哦,这是一个文件系统操作”或“那是在做网络工作”。
同时使用多个命名空间显然会导致灾难,但在我看来,使用 JUST 命名空间 std
和仅命名空间 std
并不是什么大问题,因为重新定义只能通过您自己的代码进行......
因此,只需将它们视为保留名称,如“int”或“class”,就是这样。
人们应该停止对它如此肛门。你的老师一直都是对的。只需使用一个命名空间;这就是首先使用命名空间的重点。您不应该同时使用多个。除非是你自己的。所以再一次,重新定义不会发生。
min
、end
和 less
等短字符串出现在 std::
命名空间中。但更重要的是,既然 std::
中有数千个符号,读者知道他们可能不知道的新符号来自哪里很有用。
我同意这里的其他人的观点,但我想解决关于可读性的问题——你可以通过简单地在文件、函数或类声明的顶部使用 typedefs 来避免所有这些。
我通常在我的类声明中使用它,因为类中的方法倾向于处理相似的数据类型(成员),而 typedef 是一个分配在类上下文中有意义的名称的机会。这实际上有助于类方法定义的可读性。
// Header
class File
{
typedef std::vector<std::string> Lines;
Lines ReadLines();
}
并在实施中:
// .cpp
Lines File::ReadLines()
{
Lines lines;
// Get them...
return lines;
}
相对于:
// .cpp
vector<string> File::ReadLines()
{
vector<string> lines;
// Get them...
return lines;
}
或者:
// .cpp
std::vector<std::string> File::ReadLines()
{
std::vector<std::string> lines;
// Get them...
return lines;
}
命名空间是一个命名范围。命名空间用于对相关声明进行分组,并将单独的项目分开。例如,两个单独开发的库可能使用相同的名称来引用不同的项目,但用户仍然可以同时使用两者:
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
// ...
}
重复命名空间名称可能会分散读者和作者的注意力。因此,可以声明来自特定名称空间的名称无需明确限定即可使用。例如:
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
// ...
}
命名空间为管理不同的库和不同版本的代码提供了强大的工具。特别是,它们为程序员提供了如何明确引用非本地名称的选择。
资料来源:Bjarne Stroustrup 的 C++ 编程语言概述
using namespace std
因计数不明确而引发编译错误的示例,这也是算法库中的函数。
#include <iostream>
#include <algorithm>
using namespace std;
int count = 1;
int main() {
cout << count << endl;
}
::count
——问题已解决。通常你会从 std 命名空间中获得比其他地方更多的东西,因此保留 using 命名空间指令可能会节省你的打字时间。
这是逐案的。我们希望将软件在其生命周期内的“总拥有成本”降至最低。声明“使用命名空间标准”有一些成本,但不使用它也有易读性成本。
人们正确地指出,在使用它时,当标准库引入新的符号和定义时,您的代码将停止编译,您可能会被迫重命名变量。然而,从长远来看,这可能是好的,因为如果您将关键字用于某些令人惊讶的目的,未来的维护者会暂时感到困惑或分心。
你不想要有一个叫做vector的模板,比如说,它不是其他人都知道的vector。并且因此在 C++ 库中引入的新定义的数量足够少,可能根本不会出现。进行这种更改是成本的,但成本并不高,并且通过不将 std
符号名称用于其他目的而获得的清晰度抵消了。
考虑到类、变量和函数的数量,在每一个上都声明 std::
可能会使您的代码混乱 50%,并使您更难理解。可以在一屏代码上采用的算法或方法中的步骤现在需要来回滚动才能遵循。这是一个真正的成本。可以说,这可能不是一个高成本,但否认它甚至存在的人是缺乏经验、教条主义或完全错误的。
我会提供以下规则:
std 与所有其他库不同。它是每个人基本上都需要知道的一个库,在我看来,最好将其视为语言的一部分。一般来说,即使没有其他库,使用命名空间 std 也是一个很好的例子。永远不要通过将它放在头文件中来强制决定编译单元(.cpp 文件)的作者。始终将决定权交给编译单元作者。即使在一个决定在任何地方使用 using namespace std 的项目中,也可能会罚款一些最好作为该规则的例外处理的模块。尽管命名空间功能允许您拥有许多具有相同符号定义的模块,但这样做会让人感到困惑。尽可能保持名称不同。即使不使用命名空间功能,如果您有一个名为 foo 的类并且 std 引入了一个名为 foo 的类,那么长期重命名您的类可能会更好。使用命名空间的另一种方法是通过为命名空间符号添加前缀来手动添加它们。我有两个已经使用了几十年的库,实际上都是从 C 库开始的,其中每个符号都以“AK”或“SCWin”为前缀。一般来说,这就像避免“使用”结构,但你不写双冒号。 AK::foo() 是 AKFoo()。它使代码更密集 5-10% 并且更少冗长,唯一的缺点是如果您必须使用两个具有相同前缀的此类库,您将遇到大麻烦。请注意,X Window 库在这方面非常出色,只是它们忘记了使用一些#defines:TRUE 和 FALSE 应该是 XTRUE 和 XFALSE,这与同样使用 TRUE 和 FALSE 的 Sybase 或 Oracle 建立了命名空间冲突具有不同的价值观! (在数据库的情况下是 ASCII 0 和 1!)这样做的一个特殊优点是它无缝地应用于预处理器定义,而 C++ using/namespace 系统不处理它们。这样做的一个很好的好处是,它提供了从成为项目的一部分到最终成为图书馆的有机坡度。在我的一个大型应用程序中,所有窗口类都以 Win 为前缀,所有信号处理模块都以 Mod 为前缀,等等。这些中的任何一个都几乎没有被重用的机会,因此将每个组都变成一个库并没有实际的好处,但是在几秒钟内,项目如何分解为子项目就很明显了。
它不会使您的软件或项目性能变差。在源代码开头包含命名空间还不错。 using namespace std
指令的包含根据您的需求以及您开发软件或项目的方式而有所不同。
namespace std
包含 C++ 标准函数和变量。当您经常使用 C++ 标准函数时,此命名空间很有用。
如本页所述:使用命名空间 std 的语句通常被认为是不好的做法。此语句的替代方法是在每次声明类型时使用作用域运算符 (::) 指定标识符所属的命名空间。并看到这样的观点:当您大量使用命名空间并确定不会发生冲突时,在源文件中使用“使用命名空间 std”没有问题。
有人说在源文件中包含 using namespace std
是一种不好的做法,因为您正在从该命名空间调用所有函数和变量。当您想定义一个与 namespace std
中包含的另一个函数同名的新函数时,您将重载该函数,它可能会因编译或执行而产生问题。它不会像您期望的那样编译或执行。
如本页所述:尽管该语句使我们免于键入 std:: 每当我们希望访问定义在 std 命名空间中的类或类型时,它会将整个 std 命名空间导入程序的当前命名空间。让我们举几个例子来理解为什么这可能不是一件好事......现在在开发的后期阶段,我们希望使用另一个版本的 cout,它是在一些名为“foo”的库中自定义实现的(例如) ... 请注意如何存在歧义,cout 指向哪个库?编译器可能会检测到这一点而不编译程序。在最坏的情况下,程序可能仍然编译但调用了错误的函数,因为我们从未指定标识符属于哪个命名空间。
我同意其他人的观点——它要求名称冲突、含糊不清,而事实是它不那么明确。虽然我可以看到 using
的使用,但我个人的偏好是限制它。我也会强烈考虑其他人指出的内容:
如果您想查找一个可能是相当常见的名称的函数名称,但您只想在 std
命名空间中找到它(或相反 - 您想更改所有 非的调用在命名空间 std
、命名空间 X
、...) 中,那么您打算怎么做呢?
您可以编写一个程序来完成它,但是花时间在您的项目本身上工作而不是编写一个程序来维护您的项目不是更好吗?
就个人而言,我实际上并不介意 std::
前缀。我喜欢它而不是没有它。我不知道这是否是因为它是明确的并且对我说“这不是我的代码......我正在使用标准库”或者它是否是其他东西,但我认为它看起来更好。考虑到我最近才接触到 C++(使用并且仍在使用 C 和其他语言的时间更长,而且 C 是我一直以来最喜欢的语言,就在汇编之上),这可能很奇怪。
还有另一件事,尽管它与上述内容和其他人指出的内容有些相关。虽然这可能是不好的做法,但我有时会为标准库版本保留 std::name
,并为特定于程序的实现保留名称。是的,确实这可能会咬你,咬你,但这一切都归结为我从头开始这个项目,我是它唯一的程序员。示例:我重载 std::string
并将其称为 string
。我有有用的补充。我这样做的部分原因是我的 C 和 Unix (+ Linux) 倾向于小写名称。
除此之外,您可以拥有命名空间别名。这是一个可能没有被提及的有用的示例。我使用 C++11 标准,特别是 libstdc++。好吧,它没有完整的 std::regex
支持。当然,它可以编译,但它会抛出一个异常,因为它是程序员端的错误。但它缺乏实施。
所以这就是我解决它的方法。安装 Boost 的正则表达式,并将其链接。然后,我执行以下操作,以便当 libstdc++ 完全实现它时,我只需要删除此块并且代码保持不变:
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不那么封闭,不那么傲慢,更容易接受。)。但是, 有用的是一些人已经提出的建议:我确实使用列表(它相当通用,不是吗?),并排序(同样的事情)命名两个,如果我要做using namespace std;
,因此我更喜欢具体、可控并且知道如果我打算将其作为标准用途,那么我将不得不指定它。简单地说:不允许假设。
至于让 Boost 的正则表达式成为 std
的一部分。我这样做是为了将来的整合,而且——我再次完全承认这是偏见——我不认为它像 boost::regex:: ...
那样丑陋。的确,这对我来说是另一回事。 C++ 中有很多东西在外观和方法上我还没有完全接受(另一个例子:可变参数模板与 var 参数 [尽管我承认可变参数模板非常有用!])。即使是那些我确实接受它的人也很困难,并且我仍然对他们有意见。
根据我的经验,如果您有多个使用 cout
的库,但出于不同的目的,您可能会使用错误的 cout
。
例如,如果我输入 using namespace std;
和 using namespace otherlib;
,然后只输入 cout
(恰好两者都有),而不是 std::cout
(或 'otherlib::cout'
),您可能会使用错误的,并且得到错误。使用 std::cout
更加有效和高效。
我不认为在所有情况下都一定是不好的做法,但是在使用它时需要小心。如果您正在编写一个库,您可能应该将范围解析运算符与命名空间一起使用,以防止您的库与其他库发生冲突。对于应用程序级代码,我看不出有什么问题。
对于不合格的导入标识符,您需要像 grep 这样的外部搜索工具来找出声明标识符的位置。这使得推理程序正确性变得更加困难。
这是一种不好的做法,通常称为全局命名空间污染。当多个命名空间具有相同的函数名称和签名时,可能会出现问题,那么编译器将无法决定调用哪个命名空间,而当您使用 std::cout
等函数调用指定命名空间时,这一切都可以避免.希望这可以帮助。 :)
“为什么'使用命名空间标准;'在 C++ 中被认为是不好的做法?”
我反过来说:为什么有些人认为输入五个额外的字符很麻烦?
例如,考虑编写一个数值软件。当“vector”是问题域最重要的概念之一时,为什么我什至会考虑通过将一般的“std::vector”削减为“vector”来污染我的全局命名空间?
cout << hex << setw(4) << i << endl;
比 std::cout << std::hex << std::setw(4) << i << std::endl;
更容易阅读
map<string,pair<string,string>>
相比,std::map<std::string,std::pair<std::string,std::string>>
很糟糕。
为了回答你的问题,我实际上是这样看待的:很多程序员(不是全部)调用命名空间 std。因此,人们应该养成不使用与命名空间 std 中的内容冲突或使用相同名称的东西的习惯。这是理所当然的,但与严格来说可以提出的可能连贯的单词和假名的数量相比,这并不算多。
我的意思是真的......说“不要依赖这个存在”只是让你依赖它不存在。您会经常遇到借用代码片段并不断修复它们的问题。只需将您的用户定义和借用的东西保持在应有的有限范围内,并且非常谨慎地使用全局变量(老实说,全局变量几乎总是为了“立即编译,稍后理智”的最后手段)。真的,我认为这是您老师的坏建议,因为使用 std 将适用于“cout”和“std::cout”,但不使用 std 仅适用于“std::cout”。您不会总是有幸编写自己的所有代码。
注意:在您真正了解编译器的工作原理之前,不要过多地关注效率问题。有了一点编码经验,您不必对它们了解太多,然后您就会意识到它们能够将好的代码概括为简单的东西。每一点都像你用 C 写整个东西一样简单。好的代码只有它需要的复杂程度。
<algorithm>
重新发明事物),想象同样的人可以可靠地避免这些标识符似乎有点牵强。查看您自己的代码并告诉我您从来没有一个名为 count
的变量或函数。或 distance
,或 log
,destroy
,launch
,visit
,beta
,sample
,messages
,clamp
,erase
,copy
,modulus
, left
等。更不用说所有尚未出现在 std
中的标识符,它们会在 C++35 出现时破坏您的代码......
不定期副业成功案例分享
error
、list
、sort
),IIRC 是放置它的一个重要原因进入自己的命名空间。