为什么“使用命名空间std;”认为不好的做法?

时间:2009-09-21 03:08:23

标签: c++ namespaces std using-directives c++-faq

其他人告诉我,在代码中编写using namespace std;是错误的,我应该直接使用std::coutstd::cin

为什么using namespace std;被视为不良做法?是否效率低或者是否存在声明模糊变量(与std命名空间中的函数具有相同名称的变量)的风险?它会影响性能吗?

38 个答案:

答案 0 :(得分:1987)

这与性能无关。但请考虑一下:您正在使用两个名为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()的引入将是非事件。

答案 1 :(得分:1273)

我同意所有Greg wrote,但我想补充一句: 它甚至可能比Greg说的更糟糕!

Library Foo 2.0可以引入一个函数Quux(),这对于Quux()的一些调用,明确地比你的代码多年来调用的bar::Quux()更好。然后你的 代码仍会编译 ,但是 它会默默地调用错误的函数 ,而且知道什么是神知道的。这和事情一样糟糕。

请注意,std命名空间有大量标识符,其中许多是非常常用标识符(想想listsort,{{1 }},string等)很可能也出现在其他代码中。

如果你认为这不太可能:Stack Overflow上有a question asked,在我给出这个答案后大约半年时间里发生了这种情况(由于省略了iterator前缀而被称为错误的函数)。 Here是此类问题的另一个最近的例子。 所以这是一个真正的问题。


这里还有一个数据点:许多年前,我还常常发现,必须使用std::标准库中的所有内容作为前缀。然后我在一个项目中工作,在开始时决定禁止std::指令和声明,除了函数范围。你猜怎么着?我们大部分时间都花了很长时间才习惯编写前缀,经过几周后,我们大多数人甚至同意它实际上使代码更具可读性。这是有原因的: 无论你喜欢更短或更长的散文都是主观的,但前缀客观上增加了代码的清晰度。 不仅是编译器,而且你也是找到更容易看到引用的标识符。

十年来,该项目增长了数百万行代码。由于这些讨论一次又一次地出现,我曾经很奇怪(允许的)函数范围using实际上在项目中的使用频率。我找了它的来源,只发现了一两个地方使用它。对我而言,这表明,一旦尝试过,开发人员即使在允许使用指令的情况下,即使每100 kLoC使用一次指令,也不会发现using足够痛苦。


底线:明确地为所有内容添加前缀不会造成任何伤害,很少习惯,并具有客观优势。特别是,它使编码器和人类读者更容易理解代码 - 这应该是编写代码时的主要目标。

答案 2 :(得分:369)

using namespace放在类的头文件中的问题在于它强制任何想要使用您的类(通过包含头文件)的人也可以“使用”(即看到所有内容)其他名称空间。

但是,您可以随意在(私人)* .cpp文件中添加using语句。


请注意,有些人不同意我这样的说法“感觉自由” - 因为虽然cpp文件中的using语句更好而不是标题(因为它不影响那些人包括你的头文件),他们认为它仍然不是(因为根据代码,它可能使类的实现更难维护)。 This FAQ topic说,

  

using-directive存在于遗留C ++代码中,并且可以简化向命名空间的转换,但您可能不应该定期使用它,至少不应该在新的C ++代码中使用它。

常见问题解答提出了两种选择:

  • 使用声明:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
    
  • 只需输入std ::

    即可
    std::cout << "Values:";
    

答案 3 :(得分:223)

我最近遇到了关于Visual Studio 2010的投诉。事实证明,几乎所有的源文件都有这两行:

using namespace std;
using namespace boost;

很多Boost功能都进入了C ++ 0x标准,Visual Studio 2010有很多C ++ 0x功能,所以突然间这些程序没有编译。

因此,避免using namespace X;是一种面向未来的形式,确保对正在使用的库和/或头文件的更改不会破坏程序。

答案 4 :(得分:199)

简短版本:不要在头文件中使用全局使用声明或指令。随意在实现文件中使用它们。以下是Herb Sutter和Andrei Alexandrescu在C++ Coding Standards中对此问题的看法(重点强调是我的):

  

摘要

     

命名空间使用是为了您的方便,而不是为了对其他人造成:永远不要在#include指令之前编写using声明或using指令。

     

推论:在头文件中,不要使用指令或使用声明来编写命名空间级别;相反,显式命名空间限定所有名称。 (第二个规则从第一个开始,因为标题永远不会知道其他标题#includes可能会出现在它们之后。)

     

讨论

     

简而言之:在#include指令之后,你可以而且应该在你的实现文件中使用声明和指令来使用命名空间,并且感觉良好。 尽管反复断言,使用声明和指令的命名空间并不是邪恶的,并且它们不会破坏命名空间的目的。相反,它们是使命名空间可用的原因

答案 5 :(得分:116)

不应在全局范围内使用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::sinstd::cos ...) 因为它更短,并且能够使用用户定义的浮点类型(通过Argument Dependent Lookup)。

答案 6 :(得分:94)

不要全局使用

仅当全球使用时才会被视为“不良”。这是因为:

  • 你弄乱了你正在编程的命名空间。
  • 当您使用多个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(...)`
}

这有以下魔力:

  • 编译器将为std::swap选择value_,即void std::swap(int, int)
  • 如果您实现了重载void swap(Child&, Child&),编译器将选择它。
  • 如果有重载,编译器将使用void std::swap(Child&,Child&)并尝试最佳交换。

使用C ++ 11,没有理由再使用这种模式了。 std::swap的实施已更改为发现潜在的重载并选择它。

答案 7 :(得分:75)

如果您导入了正确的标题文件,则您的全局范围内突然出现hexleftpluscount等名称。如果您不知道std::包含这些名称,这可能会令人惊讶。如果你也尝试在本地使用这些名称,可能会引起一些混乱。

如果所有标准内容都在自己的名称空间中,则不必担心与代码或其他库发生名称冲突。

答案 8 :(得分:43)

经验丰富的程序员使用任何解决问题的方法,避免出现任何问题,并且出于这个原因,它们会避免使用头文件级别的使用指令。

有经验的程序员也会尽量避免在源文件中对名称进行完全限定。造成这种情况的一个次要原因是,当代码较少时,编写更多代码并不优雅,除非有充分的理由。这样做的一个主要原因是关闭依赖于参数的查找(ADL)。

这些有什么好理由?有时程序员明确想要关闭ADL,有时他们想要消除歧义。

所以以下都可以:

  1. 函数实现
  2. 中的函数级using指令和using声明
  3. 源文件中的源文件级使用声明
  4. (有时)源文件级使用指令

答案 9 :(得分:41)

另一个原因是惊喜。

如果我看到cout << blah,而不是std::cout << blah

我认为这是cout是什么?这是正常的cout吗?这有点特别吗?

答案 10 :(得分:40)

我同意它不应该在全球范围内使用,但在本地使用并不是那么邪恶,就像在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声明声明的名称)优先于using-directive(using namespace Her_lib)在另一个作用域中可访问的名称。

答案 11 :(得分:28)

我也认为这是一种不好的做法。为什么?只有一天,我认为命名空间的功能是划分东西,所以我不应该把所有东西扔到一个全球包中来破坏它。 但是,如果我经常使用'cout'和'cin',我会在cpp文件中写入using std::cout; using std::cin;(从不在头文件中,因为它与#include一起传播)。我认为没有人会说出一个流coutcin。 ;)

答案 12 :(得分:23)

很高兴看到代码并知道代码的作用。如果我看到std::cout我知道cout库的std流。如果我看到cout,那么我就不知道了。它可能cout库的std流。或者在同一函数中可能有int cout = 0;十行更高。或者该文件中名为static的{​​{1}}变量。它可能是任何东西。

现在需要一百万行代码库,这并不是特别大,而且你正在寻找一个bug,这意味着你知道这一百万行中有一行没有做它应该做的事情。 cout可以读取名为cout << 1;的{​​{1}},将其向左移一位,然后扔掉结果。寻找一个bug,我必须检查一下。你能看到我真的更喜欢看static int吗?

如果你是一名老师,那么这些事情中的一个似乎是个好主意,而且从不必为了生活而编写和维护任何代码。我喜欢看代码,其中(1)我知道它的作用;并且,(2)我确信写作它的人知道它的作用。

答案 13 :(得分:22)

这都是关于管理复杂性的。使用命名空间会拉出你不想要的内容,从而可能使调试变得更难(我说可能)。在整个地方使用std ::更难阅读(更多文字和所有内容)。

课程中的马匹 - 以最佳方式和感觉能力来管理您的复杂性。

答案 14 :(得分:18)

同时使用多个名称空间显然是灾难的一种方法,但在我看来,使用JUST名称空间std并且只有名称空间std并不是一件大事,因为重新定义只能通过你自己的代码......

因此,只需将它们视为保留名称,如“int”或“class”即可。

人们应该停止这么肛门。你的老师一直都是对的。只需使用ONE命名空间;这是首先使用命名空间的重点。您不应该同时使用多个。除非是你自己的。因此,重新定义不会发生。

答案 15 :(得分:17)

  1. 您需要能够阅读与您有不同风格和最佳实践意见的人所编写的代码。

  2. 如果你只使用cout,没有人会感到困惑。但是当你有大量的命名空间飞来飞去并且你看到这个类而你并不完全确定它的作用时,将命名空间显式化作为一种​​评论。乍一看,你可以看到'哦,这是一个文件系统操作'或'那就是做网络的东西'。

答案 16 :(得分:17)

考虑

// myHeader.h
#include <sstream>
using namespace std;


// someoneElses.cpp/h
#include "myHeader.h"

class stringstream {  // uh oh
};

请注意,这是一个简单的示例,如果您的文件包含20个包含和其他导入,那么您将有大量的依赖关系来解决问题。更糟糕的是,根据冲突的定义,您可以在其他模块中获得无关的错误。

这并不可怕,但你不会在头文件或全局命名空间中使用它来避免头痛。在非常有限的范围内完成它可能是正常的,但是我输入额外的5个字符以解释我的功能来自哪里我从未遇到过问题。

答案 17 :(得分:12)

命名空间是命名范围。命名空间用于对相关声明进行分组并保持分离 物品分开。例如,两个单独开发的库可以使用相同的名称来表示不同的名称 项目,但用户仍然可以使用两者:

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
    / / ...
}

命名空间为管理不同的库和不同版本的库提供了强大的工具     码。特别是,它们为程序员提供了如何明确地引用非本地语言的替代方案     名。

来源:C ++编程语言概述 作者:Bjarne Stroustrup

答案 18 :(得分:11)

澄清问题的具体例子。想象一下,你有两个库,foo和bar,每个都有自己的命名空间:

namespace foo {
    void a(float) { /* does something */ }
}

namespace bar {
    ...
}

现在让我们假设您在自己的程序中使用foo和bar,如下所示:

using namespace foo;
using namespace bar;

void main() {
    a(42);
}

此时一切都很好。当你运行你的程序时,它可以做一些事情&#39;。但是稍后你更新吧,让我们说它已经变成了:

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)
}

所以你需要做一些维护来澄清哪些&#39; a&#39;你的意思(即foo::a)。这可能是不可取的,但幸运的是它非常简单(只需在foo::的所有调用前添加a,编译器将其标记为不明确的。)

但是想象一下另一种情况,其中bar改为看起来像这样:

namespace bar {
    void a(int) { /* does something completely different */ }
}

此时,您对a(42)的通话突然绑定到bar::a而不是foo::a,而不是做某事&#39;它确实有一些完全不同的东西&#39;没有编译警告或任何东西。你的程序只是默默地开始做一些完全不同的事情。

当您使用命名空间时,您可能会冒这样的情况,这就是人们使用命名空间感到不舒服的原因。命名空间中的事物越多,冲突的风险就越大,因此人们使用命名空间std(由于该命名空间中的事物数量)比其他命名空间更令人不舒服。

最终,这是可写性与可靠性/可维护性之间的权衡。可读性也可能会考虑因素,但我可以看到相反的论点。通常我会说可靠性和可维护性更重要,但在这种情况下,您将不断支付可写性成本,以获得相当罕见的可靠性/可维护性影响。最好的&#39;权衡取决于您的项目和优先事项。

答案 19 :(得分:11)

我同意这里的其他人,但是想解决有关可读性的问题 - 你可以通过在文件,函数或类声明的顶部使用typedef来避免所有这些问题。

我通常在我的类声明中使用它,因为类中的方法倾向于处理类似的数据类型(成员),而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;
}

答案 20 :(得分:9)

使用命名空间std的例子由于计数的模糊性而引发了编译错误,这也是算法库中的一个函数。

#include <iostream>

using namespace std;

int count = 1;
int main() {
    cout<<count<<endl;
}

答案 21 :(得分:8)

我认为在所有情况下都不一定是不好的做法,但是在使用它时需要小心。如果您正在编写库,则可能应该使用范围解析运算符和命名空间来保持库与其他库的对接。对于应用程序级代码,我认为没有任何问题。

答案 22 :(得分:7)

它不会使您的软件或项目性能变差,在源代码开头包含命名空间并不是很糟糕。包含using namespace std指令会根据您的需要以及您开发软件或项目的方式而有所不同。

namespace std包含C ++标准函数和变量。当您经常使用C ++标准函数时,此命名空间很有用。

  

正如本page中所述:

     

使用命名空间std的语句通常被认为是错误的   实践。此声明的替代方法是指定   标识符所属的命名空间使用范围运算符(::)   每次我们声明一个类型。

     

请参阅this opinion

     

使用&#34;使用命名空间std&#34;没有问题。在您的源文件中   当你大量使用命名空间并确定这一点时   什么都不会碰撞。

有些人说在您的源文件中包含using namespace std是一种不好的做法,因为您要从该命名空间调用所有函数和变量。如果要定义一个与namespace std中包含的另一个函数同名的新函数,则会使函数重载,并且由于编译或执行会产生问题。它不会像你期望的那样编译或执行。

  

正如本page中所述:

     

尽管该语句使我们无法输入std :: when   我们希望访问std命名空间中定义的类或类型   将整个std命名空间导入当前命名空间   该计划。让我们举几个例子来理解为什么会这样   可能不是一件好事

     

...

     

现在处于开发的后期阶段,我们希望使用另一个版本   在一些名为“foo”的库中自定义实现的cout(for   例如)

     

...

     

请注意cout指向哪个库有歧义?   编译器可能会检测到这一点,而不是编译程序。在最坏的情况下   例如,程序可能仍然编译但调用错误的函数,因为   我们从未指定标识符属于哪个命名空间。

答案 23 :(得分:6)

“为什么'使用命名空间std;'在C ++中被认为是一种不好的做法?“

我把它反过来说:为什么输入5个额外的字符被一些人认为是麻烦的?

考虑例如编写一个数字软件,当“向量”是问题领域最重要的概念之一时,为什么我会考虑通过将一般的“std :: vector”切换为“向量”来污染我的全局命名空间?

答案 24 :(得分:6)

这是一种不好的做法,通常称为全局命名空间污染。当多个命名空间具有相同的带有签名的函数名称时,可能会出现问题,那么当您使用函数调用{{1}指定命名空间时,编译器决定调用哪一个将是不明确的。 }。希望这可以帮助。 :)

答案 25 :(得分:6)

我同意其他人的意见 - 它要求名称冲突,含糊不清,然后事实是它不那么明确。虽然我可以看到使用using,但我个人的偏好是限制它。我也会强烈考虑其他人指出的内容:

如果你想找到一个可能是一个相当普通的名字的函数名,但是你只想在std命名空间中找到它(或者反过来 - 你想要改变所有不在命名空间中的调用std,名称空间X,...),那么您打算如何做到这一点?你可以编写一个程序来做这件事,但是花时间在你的项目上工作而不是编写一个程序来维护你的项目会不会更好?

我个人实际上并不介意std::前缀。我喜欢这种外观而不是拥有它。我不知道是不是因为它是明确的并且对我说'#34;这不是我的代码......我正在使用标准库&#34;或者如果它是其他东西,但我认为它看起来更好。这可能是奇怪的,因为我最近才进入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中的类/任何内容的名称是一个好主意,更具体地说,代替。字符串是例外(在这里忽略第一个,上面或第二个,如果必须,请忽略),因为我不喜欢&#39; String&#39;的想法。事实上,我仍然偏向于C并且偏向于C ++。保留细节,我工作的大部分内容更符合C(但这是一个很好的练习,也是让自己成为一个好方法。学习另一种语言和b。尽量不要偏向于对象/类/等等,这可能是更好的陈述不那么封闭,不那么傲慢,更容易接受。但是有用的是有些人已经提出的建议:我确实使用了list(它是相当通用的,不是吗?),排序(同样的事情)来命名两个如果我做{{1}会导致名称冲突所以为此我更喜欢具体,控制和知道,如果我打算将它作为标准用途,那么我将不得不指定它。简单地说:不假设允许。

至于将Boost的正则表达式作为using namespace std;的一部分。我这样做是为了未来的整合 - 再次,我完全承认这是偏见 - 我不认为它像std那样丑陋。这对我来说确实是另一回事。在C ++中有很多东西我还没有完全接受外观和方法(另一个例子:变量模板与var args [虽然我承认变量模板非常有用!])。即使是那些我接受它的人也很困难,我仍然遇到问题。

答案 26 :(得分:6)

取决于它的位置。如果它是一个公共头,那么你通过将它合并到全局命名空间来减少命名空间的值。请记住,这可能是制作模块全局变量的一种巧妙方法。

答案 27 :(得分:6)

使用非限定导入的标识符,您需要外部搜索工具(如 grep )来查找声明标识符的位置。这使得关于程序正确性的推理更加困难。

答案 28 :(得分:5)

根据我的经验,如果您有多个使用say cout的库,但出于不同的目的,您可能会使用错误的cout

例如,如果我输入using namespace std;using namespace otherlib;并输入cout(恰好是两者),而不是std::cout(或'otherlib::cout') ,你可能使用了错误的,并且得到错误,使用std::cout会更加有效和高效。

答案 29 :(得分:5)

回答你的问题我实际上是这样看的:很多程序员(不是全部)调用命名空间std。因此,人们应该养成不使用与命名空间std中的名称相同或使用相同名称的东西。这是非常重要的,但与严格来说可能出现的可能连贯的单词和假名的数量相比并没有那么多。

我的意思是真的......说“不要依赖于存在”只是让你依赖它不存在。你经常会有借用代码片段并不断修复它们的问题。只保留用户定义和借用的东西,因为它们应该是有限的,并且非常不使用全局变量(诚然,全局变量几乎总是最后用于“现在编译,后来理智”的目的)。真的,我认为这是你老师的糟糕建议,因为使用std将同时适用于“cout”和“std :: cout”但不使用std只适用于“std :: cout”。你并不总是有幸写下你自己的代码。

注意:在实际了解编译器的工作原理之前,不要过分关注效率问题。有了一点编码经验,在你意识到他们能够将优秀的代码概括为简单的东西之前,你不必了解它们。每一点都很简单,好像你用C编写了整个东西。好的代码只是它需要的复杂。

答案 30 :(得分:5)

有一个非常简单的答案:这是防御性编程。您知道std::size_t可以使std::coutusing namespace std;等的使用变得更容易 -希望您不需要确信这样的指令在标题中没有位置!但是,在翻译部门内,您可能会被吸引……

每个C ++修订版中,std命名空间一部分的类型,类等。如果您放宽std::限定词,可能会有太多歧义。 完全合理地放松std中您将经常使用的名称的限定词,例如using std::fprintf;,或更可能的是,诸如:using std::size_t; -但除非这些已经是该语言已经很好理解的部分(或者具体地说,是C库的std包装),否则请使用限定符。

当您将typedefautodecltype推论结合使用时,从可读性/可维护性的角度来看,实际上并没有任何收获。

答案 31 :(得分:4)

是的,命名空间很重要。进入我的项目后,我需要将一个var声明导入到我的源代码中,但在编译时,它与另一个第三方库冲突。

最后,我不得不通过其他方式绕过它,并使代码不那么清晰。

答案 32 :(得分:3)

#include <iostream>

using namespace std;

int main() {
  // There used to be
  // int left, right;
  // But not anymore

  if (left != right)
    std::cout << "Excuse me, WHAT?!\n";
}

那为什么呢?因为它会引入与常用变量名重叠的标识符,并让此代码进行编译,将其解释为if (std::left != std::right)

PVS-Studio可以使用V1058诊断程序找到这样的错误:https://godbolt.org/z/YZTwhp(谢谢Andrey Karpov!)。

ping cppcheck开发人员:您可能希望标记该项目。太傻了。

答案 33 :(得分:2)

我认为使用本地全球应该取决于应用程序。

由于,     当我们在本地使用库时,有时代码会变得非常混乱。可读性会降低。

所以,我们应该在只有可能发生冲突的情况下在本地使用库。

我不是更多经验的人。所以,如果我错了,请告诉我。

答案 34 :(得分:2)

老实说,对我而言,这就像讨论缩进的空格数量一样。 在标头中使用指令会导致损坏。但在c ++文件中?也许如果你一次使用2个命名空间。但如果你使用它,它更多的是风格而不是真正的效率。 你知道为什么关于缩进的线程如此受欢迎?任何人都可以说些什么,听起来很聪明,经验丰富。

答案 35 :(得分:1)

这是我在任何其他答案中找不到的观点:只使用一个命名空间。根据大多数答案,命名空间不好的主要原因是你可能会有冲突的函数名,这可能会导致整个混乱。但是,如果只使用一个命名空间,则不会发生这种情况。确定你将使用最多的库(可能是using namespace std;)并坚持下去。

可以将其视为具有不可见的库前缀 - std::vector变为vector。在我看来,这是两个世界中最好的:一方面它减少了你必须做的打字量(如命名空间所预期的那样),另一方面,它仍然要求你使用前缀来保持清晰和安全。如果有一个没有命名空间前缀的函数或对象 - 你知道它来自你声明的一个命名空间。

请记住,如果您决定全球使用 - 请勿在本地使用其他人。这回到了其他答案,本地名称空间通常比全局名称空间更有用,因为它们提供了多样化的便利性。

答案 36 :(得分:1)

视情况而定。我们希望在软件的整个生命周期内将其“总拥有成本”降至最低。声明“使用命名空间标准”会带来一些成本,但使用它也会带来可读性。

人们正确地指出,当使用std库引入新的符号和定义时,您的代码将停止编译,并且您可能被迫重命名变量。但是,这可能是一个长期的好选择,因为如果您出于某些令人惊讶的目的而使用关键字,将来的维护者会立即感到困惑或分心。您不想想要拥有一个称为vector的模板,例如,这不是其他所有人都知道的vector。因此,在C ++库中引入的新定义的数量非常小,可能根本就不会出现。 所需的费用和费用

给出类,变量和函数的数量,在每个代码上声明std ::可能会使您的代码模糊不清50%,从而使您的工作更加困难。现在,可以在一个屏幕代码中采用的算法或方法中的步骤要求前后滚动才能跟随。这是实际成本。可以说这可能不是很高的代价,但是否认它甚至存在的人是没有经验的,教条主义的或​​完全错误的。

我将提供以下规则:

  1. std与所有其他库不同。它是每个人基本都需要知道的一个库,在我看来,最好将其视为语言的一部分。一般来说,using namespace std有一个很好的案例,即使没有其他库也没有。

  2. 决不要通过在标头中使用来将决定强加给编译单元(.cpp文件)的作者。 总是将决定推迟到编译部门的作者。即使在一个决定在所有地方都使用using namespace std的项目中,可能会罚款一些最好作为该规则例外处理的模块。

  3. 即使命名空间功能使您可以使用定义相同的符号的许多模块,但这样做会令人困惑。尽可能保持名称不同。即使不使用命名空间功能,如果您有一个名为foo的类,并且std引入了一个名为foo的类,则长期而言最好还是重命名该类。

  4. 使用名称空间的另一种方法是通过给名称符号加上前缀来手动命名它们。我有两个已经使用了数十年的库,实际上都是从C库开始的,其中每个符号都以“ AK”或“ SCWin”开头。一般来说,这就像避免使用“ using”构造,但是您不必编写双冒号。 AK :: foo()相反是AKFoo()。它使代码的密度提高了5-10%,且冗长程度降低了,唯一的缺点是,如果必须使用两个具有相同前缀的此类库,将会遇到很大的麻烦。请注意,X-Windows库在这方面非常出色,只是它们忘记了以下几个#define:TRUE和FALSE应该是XTRUE和XFALSE,这与Sybase或Oracle建立了名称空间冲突,它们也使用TRUE和值不同则为假! (对于数据库,是ASCII 0和1!)它的一个特殊优点是,它似乎适用于预处理器定义,而C ++ using / namespace系统不处理它们。这样做的一个好处是,它为从项目的一部分到最终成为图书馆提供了有机的倾斜。在我的一个大型应用程序中,所有窗口类都以Win为前缀,所有信号处理模块都以Mod为前缀,等等。将这些组重用的可能性很小,因此将每个组合并为一个库并没有任何实际好处,但是在几秒钟内就可以清楚地看出该项目是如何分成子项目的。

答案 37 :(得分:1)

命名空间是为了避免命名冲突。 C ++基于C,并且C在函数和变量名方面存在许多问题,因为有时来自不同库的函数会发生冲突。因此,库开发人员开始使用如下库名称为函数添加前缀:

foo/foo.h

void libfoo_foo_foo_h_open(); // the name can be weird then even this one!

C ++引入了名称空间来轻松解决此问题。

假设您有两个名为filewindow的库,分别处理文件和窗口以及以下代码:

#include <file.h>
#include <window.h>

using namespace file;
using namespace window;

void open() {
     ...
}

file.h

namespace file {
    void open(); // What!
}

window.h

namespace file {
    void open(); // Oh no!
}

上面的代码肯定会编译失败。

如果您不喜欢键入std::(仅5个字符),则可以始终这样做:(在头文件中不是个好主意)

using s = std;

如果您仍要在源文件中使用using namespace std;,那么您正在引发该问题,我必须问您“ 名称空间的目的是什么?”。

>