“使用命名空间 std”有什么问题?

发布于 2024-08-05 11:25:14 字数 170 浏览 8 评论 0原文

我听说 using namespace std; 是错误的,我应该直接使用 std::coutstd::cin

这是为什么呢?声明与 std 命名空间中的内容同名的变量是否存在风险?对性能有影响吗?

I have heard using namespace std; is wrong, and that I should use std::cout and std::cin directly instead.

Why is this? Does it risk declaring variables that share the same name as something in the std namespace? Are there performance implications?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(30

jJeQQOZ5 2024-08-12 11:25:15

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

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++ 编程语言概述
作者:比亚尼·斯特鲁斯特鲁普

A namespace is a named scope. Namespaces are used to group related declarations and to keep separate
items separate. For example, two separately developed libraries may use the same name to refer to different
items, but a user can still use both:

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

Repeating a namespace name can be a distraction for both readers and writers. Consequently, it is possible
to state that names from a particular namespace are available without explicit qualification. For example:

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

Namespaces provide a powerful tool for the management of different libraries and of different versions of code. In particular, they offer the programmer alternatives of how explicit to make a reference to a nonlocal name.

Source: An Overview of the C++ Programming Language
by Bjarne Stroustrup

我做我的改变 2024-08-12 11:25:15

这是一个 using namespace std 因 count 的歧义而引发编译错误的示例,count 也是算法库中的一个函数。

#include <iostream>
#include <algorithm>

using namespace std;

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

An example where using namespace std throws a compilation error because of the ambiguity of count, which is also a function in algorithm library.

#include <iostream>
#include <algorithm>

using namespace std;

int count = 1;
int main() {
    cout << count << endl;
}
睫毛溺水了 2024-08-12 11:25:15

这是具体情况而定。我们希望最大限度地降低软件在其生命周期内的“总拥有成本”。声明“使用命名空间 std”会产生一些成本,但使用它也会在易读性方面产生成本。

人们正确地指出,在使用它时,当标准库引入新的符号和定义时,您的代码将停止编译,并且您可能被迫重命名变量。然而,从长远来看,这可能是好的,因为如果您将关键字用于某些令人惊讶的目的,未来的维护人员会暂时感到困惑或分心。

例如,您想要有一个名为向量的模板,它不是其他人都知道的向量。而且 C++ 库中引入的新定义数量足够少,可能根本不会出现。进行此类更改是有成本的,但成本并不高,并且可以被不将 std 符号名称用于其他目的而获得的清晰度所抵消。

考虑到类、变量和函数的数量,在每个类、变量和函数上都声明 std:: 可能会使您的代码混乱 50%,并使您更难以理解。可以在一屏代码上采用的算法或方法中的步骤现在需要来回滚动才能跟随。这是真实的成本。可以说,这可能成本并不高,但否认它存在的人要么缺乏经验,要么教条主义,或者根本就是错误的。

我提供以下规则:

  1. std 与所有其他库不同。它是每个人基本上都需要了解的一个库,在我看来最好将其视为语言的一部分。一般来说,即使其他库没有,使用命名空间 std 也是一个很好的例子。

  2. 切勿通过将此 using 放入标头中来将决定强加给编译单元(.cpp 文件)的作者。 始终将决定推迟给编译单元作者。即使在一个已决定在所有地方使用 using namespace std 的项目中,也可能会罚款一些最好作为该规则的例外处理的模块。

  3. 尽管命名空间功能允许您拥有许多具有相同定义符号的模块,但这样做会很混乱。尽可能保持名称不同。即使不使用命名空间功能,如果您有一个名为 foo 的类,并且 std 引入了一个名为 foo 的类,从长远来看可能会更好无论如何都要重命名您的类。

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

It's case by case. We want to minimize the "total cost of ownership" of the software over its lifespan. Stating "using namespace std" has some costs, but not using it also has a cost in legibility.

People correctly point out that when using it, when the standard library introduces new symbols and definitions, your code ceases to compile, and you may be forced to rename variables. And yet this is probably good long-term, since future maintainers will be momentarily confused or distracted if you're using a keyword for some surprising purpose.

You don't want to have a template called vector, say, which isn't the vector known by everyone else. And the number of new definitions thus introduced in the C++ library is small enough it may simply not come up. There is a cost to having to do this kind of change, but the cost is not high and is offset by the clarity gained by not using std symbol names for other purposes.

Given the number of classes, variables, and functions, stating std:: on every one might fluff up your code by 50% and make it harder to get your head around. An algorithm or step in a method that could be taken in on one screenful of code now requires scrolling back and forth to follow. This is a real cost. Arguably it may not be a high cost, but people who deny it even exists are inexperienced, dogmatic, or simply wrong.

I'd offer the following rules:

  1. std is different from all other libraries. It is the one library everyone basically needs to know, and in my view is best thought of as part of the language. Generally speaking there is an excellent case for using namespace std even if there isn't for other libraries.

  2. Never force the decision onto the author of a compilation unit (a .cpp file) by putting this using in a header. Always defer the decision to the compilation unit author. Even in a project that has decided to use using namespace std everywhere may fine a few modules that are best handled as exceptions to that rule.

  3. Even though the namespace feature lets you have many modules with symbols defined the same, it's going to be confusing to do so. Keep the names different to the extent possible. Even if not using the namespace feature, if you have a class named foo and std introduces a class named foo, it's probably better long-run to rename your class anyway.

  4. An alternative to using namespaces is to manually namespace symbols by prefixing them. I have two libraries I've used for decades, both starting as C libraries, actually, where every symbol is prefixed with "AK" or "SCWin". Generally speaking, this is like avoiding the "using" construct, but you don't write the twin colons. AK::foo() is instead AKFoo(). It makes code 5-10% denser and less verbose, and the only downside is that you'll be in big trouble if you have to use two such libraries that have the same prefixing. Note the X Window libraries are excellent in this regard, except they forgot to do so with a few #defines: TRUE and FALSE should have been XTRUE and XFALSE, and this set up a namespace clash with Sybase or Oracle that likewise used TRUE and FALSE with different values! (ASCII 0 and 1 in the case of the database!) One special advantage of this is that it applies seemlessly to preprocessor definitions, whereas the C++ using/namespace system doesn't handle them. A nice benefit of this is that it gives an organic slope from being part of a project to eventually being a library. In a large application of mine, all window classes are prefixed Win, all signal-processing modules Mod, and so on. There's little chance of any of these being reused so there's no practical benefit to making each group into a library, but it makes obvious in a few seconds how the project breaks into sub-projects.

向地狱狂奔 2024-08-12 11:25:15

它不会使您的软件或项目性能变差。在源代码的开头包含命名空间也不错。 using namespace std 指令的包含情况根据您的需求以及开发软件或项目的方式而有所不同。

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

正如页面中提到的:< /p>

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

请参阅此意见:

在源文件中使用“using namespace std”没有问题
当您大量使用名称空间并确定
没有任何东西会发生碰撞。

有些人说在源文件中包含 using namespace std 是一种不好的做法,因为您是从该命名空间调用所有函数和变量。当您想要定义一个与命名空间 std 中包含的另一个函数同名的新函数时,您将重载该函数,并且可能会因编译或执行而产生问题。它不会按您的预期编译或执行。

正如页面中提到的:< /p>

尽管该语句使我们不必在任何时候输入 std::
我们希望访问 std 命名空间中定义的类或类型,它
将整个 std 命名空间导入到当前命名空间中
的程序。让我们举几个例子来理解为什么会这样
可能不是什么好事

...

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

...

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

It doesn't make your software or project performance worse. The inclusion of the namespace at the beginning of your source code isn't bad. The inclusion of the using namespace std instruction varies according to your needs and the way you are developing the software or project.

The namespace std contains the C++ standard functions and variables. This namespace is useful when you often would use the C++ standard functions.

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.

Some people had said that is a bad practice to include the using namespace std in your source files because you're invoking from that namespace all the functions and variables. When you would like to define a new function with the same name as another function contained in the namespace std you would overload the function and it could produce problems due to compile or execute. It will not compile or executing as you expect.

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.

鸠魁 2024-08-12 11:25:15

我同意其他人的观点——它要求名称冲突、含糊不清,但事实是它不太明确。虽然我可以看到 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(但这是一个很好的练习,也是让自己 a. 学习另一种语言 b. 尽量不要对对象/类/等有偏见的好方法,这可能是更好的表述思想不那么封闭,不那么傲慢,更容易接受。)。但有用的是一些人已经建议的:我确实使用列表(它相当通用,不是吗?)和排序(相同的东西)来命名两个,如果我要using namespace std;,因此为此目的,我更喜欢具体、可控,并且知道如果我打算将其作为标准用途,那么我将必须指定它。简而言之:不允许假设。

至于让 Boost 的正则表达式成为 std 的一部分。我这样做是为了将来的集成 - 再次,我完全承认这是偏见 - 我不认为它像 boost::regex:: ... 那样丑陋。确实,这对我来说是另一回事。 C++ 中有很多东西在外观和方法上我还没有完全接受(另一个例子:可变参数模板与 var 参数[尽管我承认可变参数模板非常非常有用!])。即使那些我确实接受这一点的人也很困难,我仍然对他们有意见。

I agree with others – it is asking for name clashes, ambiguities and then the fact is it is less explicit. While I can see the use of using, my personal preference is to limit it. I would also strongly consider what some others pointed out:

If you want to find a function name that might be a fairly common name, but you only want to find it in the std namespace (or the reverse – you want to change all calls that are not in namespace std, namespace X, ...), then how do you propose to do this?

You could write a program to do it, but wouldn't it be better to spend time working on your project itself rather than writing a program to maintain your project?

Personally, I actually don't mind the std:: prefix. I like the look more than not having it. I don't know if that is because it is explicit and says to me "this isn't my code... I am using the standard library" or if it is something else, but I think it looks nicer. This might be odd given that I only recently got into C++ (used and still do C and other languages for much longer and C is my favourite language of all time, right above assembly).

There is one other thing although it is somewhat related to the above and what others point out. While this might be bad practise, I sometimes reserve std::name for the standard library version and name for program-specific implementation. Yes, indeed this could bite you and bite you hard, but it all comes down to that I started this project from scratch, and I'm the only programmer for it. Example: I overload std::string and call it string. I have helpful additions. I did it in part because of my C and Unix (+ Linux) tendency towards lower-case names.

Besides that, you can have namespace aliases. Here is an example of where it is useful that might not have been referred to. I use the C++11 standard and specifically with libstdc++. Well, it doesn't have complete std::regex support. Sure, it compiles, but it throws an exception along the lines of it being an error on the programmer's end. But it is lack of implementation.

So here's how I solved it. Install Boost's regex, and link it in. Then, I do the following so that when libstdc++ has it implemented entirely, I need only remove this block and the code remains the same:

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

I won't argue on whether that is a bad idea or not. I will however argue that it keeps it clean for my project and at the same time makes it specific: True, I have to use Boost, but I'm using it like the libstdc++ will eventually have it. Yes, starting your own project and starting with a standard (...) at the very beginning goes a very long way with helping maintenance, development and everything involved with the project!

Just to clarify something: I don't actually think it is a good idea to use a name of a class/whatever in the STL deliberately and more specifically in place of. The string is the exception (ignore the first, above, or second here, pun if you must) for me as I didn't like the idea of 'String'.

As it is, I am still very biased towards C and biased against C++. Sparing details, much of what I work on fits C more (but it was a good exercise and a good way to make myself a. learn another language and b. try not be less biased against object/classes/etc which is maybe better stated as less closed-minded, less arrogant, and more accepting.). But what is useful is what some already suggested: I do indeed use list (it is fairly generic, is it not ?), and sort (same thing) to name two that would cause a name clash if I were to do using namespace std;, and so to that end I prefer being specific, in control and knowing that if I intend it to be the standard use then I will have to specify it. Put simply: no assuming allowed.

And as for making Boost's regex part of std. I do that for future integration and – again, I admit fully this is bias - I don't think it is as ugly as boost::regex:: .... Indeed, that is another thing for me. There are many things in C++ that I still have yet to come to fully accept in looks and methods (another example: variadic templates versus var arguments [though I admit variadic templates are very very useful!]). Even those that I do accept it was difficult, and I still have issues with them.

半衬遮猫 2024-08-12 11:25:15

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

例如,如果我输入 using namespace std;using namespace otherlib; 并仅键入 cout (两者恰好都存在) ,而不是 std::cout (或 'otherlib::cout'),您可能会使用错误的,并出现错误。使用 std::cout 更加有效和高效。

From my experiences, if you have multiple libraries that uses say, cout, but for a different purpose you may use the wrong cout.

For example, if I type in, using namespace std; and using namespace otherlib; and type just cout (which happens to be in both), rather than std::cout (or 'otherlib::cout'), you might use the wrong one, and get errors. It's much more effective and efficient to use std::cout.

暗藏城府 2024-08-12 11:25:15

我不认为在所有情况下这都一定是不好的做法,但使用时需要小心。如果您正在编写一个库,您可能应该将范围解析运算符与名称空间一起使用,以防止您的库与其他库发生冲突。对于应用程序级别的代码,我没有发现任何问题。

I do not think it is necessarily bad practice under all conditions, but you need to be careful when you use it. If you're writing a library, you probably should use the scope resolution operators with the namespace to keep your library from butting heads with other libraries. For application level code, I don't see anything wrong with it.

不气馁 2024-08-12 11:25:15

对于不合格的导入标识符,您需要 grep 等外部搜索工具来查找声明标识符的位置。这使得推理程序正确性变得更加困难。

With unqualified imported identifiers you need external search tools like grep to find out where identifiers are declared. This makes reasoning about program correctness harder.

明明#如月 2024-08-12 11:25:15

为什么要避免using namespace std;

原因 1:避免名称冲突。

由于 C++ 标准库很大且不断扩展,因此命名空间在 C++ 中用于减少名称冲突。当您使用“using namespace std;”时,您正在批量导入所有内容。

这就是为什么“使用命名空间 std;”永远不会出现在任何专业代码中。

原因2:编译失败。

因为它将std命名空间中定义的数百个东西(类、方法、常量、模板等)拉入全局命名空间。它不仅对写入“using namespace std”本身的文件这样做,而且对包含它的任何文件都递归地这样做。这很容易导致意外的 ODR 违规和难以调试的编译器/链接器错误。

示例

当您在全局命名空间中声明函数“max”时,您将使用 std 命名空间。

由于您没有使用 cmath 标头,因此一切似乎都运行良好。

当其他人包含您的文件和 cmath 标头时,他们的代码会意外地无法构建,因为全局命名空间中有两个名为“max”的函数。

原因 3:将来可能不起作用。

更糟糕的是,您无法预测将来会对 std:: 命名空间进行哪些更改。这意味着如果新添加的符号与代码中的某些内容发生冲突,今天运行的代码可能会在以后停止运行。

原因 4:难以维护和调试。

使用命名空间 std; 会产生难以维护和调试的代码。这是因为某些方面的来源并不总是显而易见。如果开发人员使用术语“字符串”而没有更多解释,则他们可能指的是 std::string 类或唯一字符串类。


带有命名空间std的代码

#include <iostream>
#include <algorithm>

using namespace std;

int swap = 0;

int main() {
    cout << swap << endl; // ERROR: reference to "swap" is ambiguous
}

没有命名空间

#include <iostream>

int main() {
    using std::cout; // This only affects the current function

    cout << "Hello" <<'\n';
}

但是你可以使用if,

  • 如果你想制作简短的教程或程序等,你可以使用它。

  • 当您大量使用命名空间并且确信不会发生冲突时,在源文件中使用“using namespace std”没有问题。

Why should using namespace std; be avoided?

Reason 1: To avoid name collision.

Because the C++ standard library is large and constantly expanding, namespaces in C++ are used to lessen name collisions. You are importing everything wholesale when you use "using namespace std;".

That's why "using namespace std;" will never appear in any professional code.

Reason 2: Failed compilation.

Because it pulls the hundreds of things (classes, methods, constants, templates, etc.) defined in the std namespace into the global namespace. And it does so, not just for the file that writes “using namespace std” itself, but also for any file that includes it, recursively. This can very easily lead to accidental ODR violations and hard-to-debug compiler/linker errors.

Example:

You use the std namespace when you declare the function "max" in the global namespace.

Since you aren't using the cmath header, everything appears to be working well.

When someone else includes your file and the cmath header, their code unexpectedly fails to build because there are two functions with the name "max" in the global namespace.

Reason 3: May not work in future.

Even worse, you can't predict what changes will be made to the std:: namespace in the future. This means that code that functions today might cease to function later if a newly added symbol clashes with something in your code.

Reason 4: Difficult to maintain and debug.

The use of namespace std; can produce difficult-to-maintain and difficult-to-debug code. This is due to the fact that it is not always obvious where certain aspects come from. A developer might be referring to the std::string class or a unique string class if they use the term "string" without more explanation.


Code with namespace std

#include <iostream>
#include <algorithm>

using namespace std;

int swap = 0;

int main() {
    cout << swap << endl; // ERROR: reference to "swap" is ambiguous
}

Without namespace

#include <iostream>

int main() {
    using std::cout; // This only affects the current function

    cout << "Hello" <<'\n';
}

But you can use if,

  • you can use that if want to make short tutorials or programs, etc.

  • 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.

ヅ她的身影、若隐若现 2024-08-12 11:25:15

这通常称为全局名称空间污染。当多个命名空间具有相同的函数名和签名时,可能会出现问题,那么编译器决定调用哪一个命名空间将是不明确的,而当您使用像 这样的函数调用指定命名空间时,这一切都可以避免std::cout

This is often known as global namespace pollution. Problems may occur when more than one namespace has the same function name with signature, then it will be ambiguous for the compiler to decide which one to call and this all can be avoided when you are specifying the namespace with your function call like std::cout.

九命猫 2024-08-12 11:25:15

我反过来说:为什么有些人认为额外输入五个字符很麻烦?

例如,考虑编写一个数值软件。当 vector 为 1 时,为什么我会考虑通过将常规 std::vector 缩减为 vector 来污染我的全局命名空间问题领域最重要的概念是什么?

I put it the other way around: Why is typing five extra characters considered cumbersome by some?

Consider e.g. writing a piece of numerical software. Why would I even consider polluting my global namespace by cutting general std::vector<T> down to vector<T> when vector is one of the problem domain's most important concepts?

风流物 2024-08-12 11:25:14

考虑两个名为 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() 将会已经成为一个非事件。

Consider two libraries called Foo and Bar:

using namespace foo;
using namespace bar;

Everything works fine, and you can call Blah() from Foo and Quux() from Bar without problems. But one day you upgrade to a new version of Foo 2.0, which now offers a function called Quux(). Now you've got a conflict: Both Foo 2.0 and Bar import Quux() into your global namespace. This is going to take some effort to fix, especially if the function parameters happen to match.

If you had used foo::Blah() and bar::Quux(), then the introduction of foo::Quux() would have been a non-event.

薄情伤 2024-08-12 11:25:14

的更糟糕!

它可能会比 Greg写 Foo 2.0 可以引入一个函数 Quux(),对于您对 Quux() 的某些调用来说,它比 bar::Quux( ) 你的代码调用了很多年。然后你的代码仍然可以编译,但是它默默地调用了错误的函数并且做了天知道什么的事情。这就是事情所能达到的最糟糕的情况了。

请记住,std 命名空间有大量标识符,其中许多非常常见(例如 listsort、stringiterator 等)也很可能出现在其他代码中。

如果您认为这不太可能:Stack Overflow 上有一个问题,几乎正是发生了这种情况(错误的函数称为 due在我给出这个答案大约半年后,省略了 std:: 前缀。 这里是此类问题的另一个最新示例。
所以这是一个真正的问题。


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

十年内,该项目增长到拥有数百万行代码。由于这些讨论一次又一次地出现,我曾经很好奇(允许的)函数范围 using 在项目中实际使用的频率。我查找了它的来源,只找到了一两打使用它的地方。对我来说,这表明,一旦尝试过,开发人员不会觉得 std:: 足以痛苦地使用 using 指令,即使每 100 kLoC 一次,即使在允许使用它的地方也是如此。


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

It can get worse than what Greg wrote!

Library Foo 2.0 could introduce a function, Quux(), that is an unambiguously better match for some of your calls to Quux() than the bar::Quux() your code called for years. Then your code still compiles, but it silently calls the wrong function and does god-knows-what. That's about as bad as things can get.

Keep in mind that the std namespace has tons of identifiers, many of which are very common ones (think list, sort, string, iterator, etc.) which are very likely to appear in other code, too.

If you consider this unlikely: There was a question asked here on Stack Overflow where pretty much exactly this happened (wrong function called due to omitted std:: prefix) about half a year after I gave this answer. Here is another, more recent example of such a question.
So this is a real problem.


Here's one more data point: Many, many years ago, I also used to find it annoying having to prefix everything from the standard library with std::. Then I worked in a project where it was decided at the start that both using directives and declarations are banned except for function scopes. Guess what? It took most of us very few weeks to get used to writing the prefix, and after a few more weeks most of us even agreed that it actually made the code more readable. There's a reason for that: Whether you like shorter or longer prose is subjective, but the prefixes objectively add clarity to the code. Not only the compiler, but you, too, find it easier to see which identifier is referred to.

In a decade, that project grew to have several million lines of code. Since these discussions come up again and again, I once was curious how often the (allowed) function-scope using actually was used in the project. I grep'd the sources for it and only found one or two dozen places where it was used. To me this indicates that, once tried, developers don't find std:: painful enough to employ using directives even once every 100 kLoC even where it was allowed to be used.


Bottom line: Explicitly prefixing everything doesn't do any harm, takes very little getting used to, and has objective advantages. In particular, it makes the code easier to interpret by the compiler and by human readers — and that should probably be the main goal when writing code.

<逆流佳人身旁 2024-08-12 11:25:14

using namespace 放入类的头文件中的问题在于,它迫使任何想要使用您的类(通过包含头文件)的人也“使用”(即查看其中的所有内容)那些其他命名空间。

但是,您可以随意将 using 语句放入您的(私有)*.cpp 文件中。


请注意,有些人不同意我这样说“随意”——因为虽然 cpp 文件中的 using 语句比标头中的更好(因为它不不会影响包含您的头文件的人),他们认为这仍然不好(因为根据代码,它可能会使类的实现更难以维护)。 此 C++ 超级常见问题解答条目 说,

using-directive 存在于旧版 C++ 代码中,旨在简化到命名空间的转换,但您可能不应该定期使用它,至少不应该在新的 C++ 代码中使用它。

常见问题解答建议了两种替代方案:

  • 使用声明:

    使用 std::cout; // using 声明让您无需限定即可使用 cout
    计算<< “价值观:”;
    
  • 只需输入 std::

    std::cout << “价值观:”;
    

The problem with putting using namespace in the header files of your classes is that it forces anyone who wants to use your classes (by including your header files) to also be 'using' (i.e. seeing everything in) those other namespaces.

However, you may feel free to put a using statement in your (private) *.cpp files.


Beware that some people disagree with my saying "feel free" like this -- because although a using statement in a cpp file is better than in a header (because it doesn't affect people who include your header file), they think it's still not good (because depending on the code it could make the implementation of the class more difficult to maintain). This C++ Super-FAQ entry says,

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.

The FAQ suggests two alternatives:

  • A using-declaration:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
    
  • Just typing std::

    std::cout << "Values:";
    
谎言月老 2024-08-12 11:25:14

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

using namespace std;
using namespace boost;

很多 Boost 功能正在纳入 C++0x 标准,而 Visual Studio 2010 有很多 C++0x 功能,因此突然间这些程序无法编译。

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

I recently ran into a complaint about Visual Studio 2010. It turned out that pretty much all the source files had these two lines:

using namespace std;
using namespace boost;

A lot of Boost features are going into the C++0x standard, and Visual Studio 2010 has a lot of C++0x features, so suddenly these programs were not compiling.

Therefore, avoiding using namespace X; is a form of future-proofing, a way of making sure a change to the libraries and/or header files in use is not going to break a program.

陌上芳菲 2024-08-12 11:25:14

简短版本:不要在头文件中使用全局 using 声明或指令。请随意在实现文件中使用它们。以下是 Herb SutterAndrei Alexandrescu 必须在 C++ 编码标准(粗体表示强调是我的):

摘要

命名空间 using 是为了您的方便,而不是为了您对他人造成伤害:切勿在 #include 指令之前编写 using 声明或 using 指令。

推论:在头文件中,不要编写命名空间级别的 using 指令或 using 声明;相反,显式地对所有名称进行命名空间限定。 (第二条规则遵循第一条规则,因为标头永远无法知道在它们之后可能出现其他标头 #includes。)

讨论

简而言之:您可以而且应该在 #include 指令之后在实现文件中自由地使用命名空间 using 声明和指令,并且对此感觉良好。 尽管不断提出相反的主张,但命名空间使用声明和指令并不是邪恶的,它们不会违背命名空间的目的。相反,它们使命名空间变得可用

Short version: don't use global using declarations or directives in header files. Feel free to use them in implementation files. Here's what Herb Sutter and Andrei Alexandrescu have to say about this issue in C++ Coding Standards (bolding for emphasis is mine):

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.

○闲身 2024-08-12 11:25:14

不应在全局范围内使用 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...)要好,因为它更短并且能够使用用户定义的浮点类型(通过 参数相关查找< /a>(ADL))。

One shouldn't use the using directive at the global scope, especially in headers. However, there are situations where it is appropriate even in a header file:

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

This is better than explicit qualification (std::sin, std::cos...), because it is shorter and has the ability to work with user defined floating point types (via argument-dependent lookup (ADL)).

一杆小烟枪 2024-08-12 11:25:14

不要在全球范围内使用它

只有在全球范围内使用时才被认为是“坏”的。因为:

  • 您正在编程的命名空间变得混乱。
  • 当您使用许多 using namespace xyz; 时,读者将很难看到特定标识符的来源。
  • 对于源代码的其他读者来说是正确的,对于最常阅读源代码的读者(您自己)来说更是如此。一两年后回来看看...
  • 如果您只谈论 using namespace std; 您可能不会意识到您抓取的所有内容 - 当您添加另一个>#include 或迁移到新的 C++ 修订版,您可能会遇到您不知道的名称冲突。

您可以在本地使用它

继续并在本地(几乎)自由地使用它。当然,这可以防止您重复 std:: ——而且重复也是不好的。

在本地使用它的习惯用法

C++03中,有一个习惯用法——样板代码——用于为类实现交换函数。建议您实际使用本地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 的实现已更改,以查找潜在的重载并选择它。

Do not use it globally

It is considered "bad" only when used globally. Because:

  • You clutter the namespace you are programming in.
  • Readers will have difficulty seeing where a particular identifier comes from, when you use many using namespace xyz;.
  • Whatever is true for other readers of your source code is even more true for the most frequent reader of it: yourself. Come back in a year or two and take a look...
  • If you only talk about using namespace std; you might not be aware of all the stuff you grab -- and when you add another #include or move to a new C++ revision you might get name conflicts you were not aware of.

You may use it locally

Go ahead and use it locally (almost) freely. This, of course, prevents you from repetition of std:: -- and repetition is also bad.

An idiom for using it locally

In C++03 there was an idiom -- boilerplate code -- for implementing a swap function for your classes. It was suggested that you actually use a local using namespace std; -- or at least 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(...)`
}

This does the following magic:

  • The compiler will choose the std::swap for value_, i.e. void std::swap(int, int).
  • If you have an overload void swap(Child&, Child&) implemented the compiler will choose it.
  • If you do not have that overload the compiler will use void std::swap(Child&,Child&) and try its best swapping these.

With C++11 there is no reason to use this pattern any more. The implementation of std::swap was changed to find a potential overload and choose it.

若有似无的小暗淡 2024-08-12 11:25:14

如果导入正确的头文件,您会突然得到类似 hexpluscount 在您的全局范围内。如果您不知道 std:: 包含这些名称,这可能会令人惊讶。如果您还尝试在本地使用这些名称,可能会导致相当多的混乱。

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

If you import the right header files you suddenly have names like hex, left, plus or count in your global scope. This might be surprising if you are not aware that std:: contains these names. If you also try to use these names locally it can lead to quite some confusion.

If all the standard stuff is in its own namespace you don't have to worry about name collisions with your code or other libraries.

菊凝晚露 2024-08-12 11:25:14

另一个原因是惊喜。

如果我看到 cout << blah,而不是 std::cout <<等等我想:这个cout是什么?这是正常的cout吗?有什么特别的吗?

Another reason is surprise.

If I see cout << blah, instead of std::cout << blah I think: What is this cout? Is it the normal cout? Is it something special?

随梦而飞# 2024-08-12 11:25:14

我同意它不应该在全局使用,但在本地使用也没有那么邪恶,就像在命名空间中一样。以下是“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 指令(using namespace Her_lib)在另一个作用域中访问的名称)。

I agree that it should not be used globally, but it's not so evil to use locally, like in a namespace. Here's an example from "The C++ Programming Language":

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

}

In this example, we resolved potential name clashes and ambiguities arising from their composition.

Names explicitly declared there (including names declared by using-declarations like His_lib::String) take priority over names made accessible in another scope by a using-directive (using namespace Her_lib).

゛清羽墨安 2024-08-12 11:25:14

有经验的程序员使用任何可以解决问题的方法,并避免任何产生新问题的方法,并且出于这个确切的原因,他们避免使用头文件级的 using 指令。

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

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

因此,以下内容是可以的:

  1. 函数实现中的函数级 using-directives 和 using-declarations
  2. 源文件中的源文件级 using-declarations
  3. (有时) 源文件级 using-directives

Experienced programmers use whatever solves their problems and avoid whatever creates new problems, and they avoid header-file-level using-directives for this exact reason.

Experienced programmers also try to avoid full qualification of names inside their source files. A minor reason for this is that it's not elegant to write more code when less code is sufficient unless there are good reasons. A major reason for this is turning off argument-dependent lookup (ADL).

What are these good reasons? Sometimes programmers explicitly want to turn off ADL, other times they want to disambiguate.

So the following are OK:

  1. Function-level using-directives and using-declarations inside functions' implementations
  2. Source-file-level using-declarations inside source files
  3. (Sometimes) source-file-level using-directives
一影成城 2024-08-12 11:25:14

我也认为这是一种不好的做法。为什么?就在有一天,我认为命名空间的功能是划分东西,所以我不应该把所有东西都扔进一个全局包里,从而破坏它。

但是,如果我经常使用“cout”和“cin”,我会写: using std::cout;在 .cpp 文件中使用 std::cin;(切勿在头文件中使用,因为它通过 #include 传播)。我认为没有一个理智的人会将流命名为 coutcin。 ;)

I also consider it a bad practice. Why? Just one day I thought that the function of a namespace is to divide stuff, so I shouldn't spoil it with throwing everything into one global bag.

However, if I often use 'cout' and 'cin', I write: using std::cout; using std::cin; in the .cpp file (never in the header file as it propagates with #include). I think that no one sane will ever name a stream cout or cin. ;)

桃气十足 2024-08-12 11:25:14

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

现在,采用一百万行代码库,这并不是特别大,并且您正在寻找错误,这意味着您知道这一百万行中有一行没有执行其应该执行的操作。 cout << 1; 可以读取一个名为 coutstatic int,将其左移一位,然后丢弃结果。寻找错误,我必须检查一下。你能看出我是多么喜欢看到 std::cout 吗?

如果您是一名教师并且从未以编写和维护任何代码为生,那么这似乎是一个非常好的主意。我喜欢看到以下代码:(1) 我知道它的作用;并且,(2) 我相信编写它的人知道它的作用。

It's nice to see code and know what it does. If I see std::cout I know that's the cout stream of the std library. If I see cout then I don't know. It could be the cout stream of the std library. Or there could be an int cout = 0; ten lines higher in the same function. Or a static variable named cout in that file. It could be anything.

Now take a million line code base, which isn't particularly big, and you're searching for a bug, which means you know there is one line in this one million lines that doesn't do what it is supposed to do. cout << 1; could read a static int named cout, shift it to the left by one bit, and throw away the result. Looking for a bug, I'd have to check that. Can you see how I really really prefer to see std::cout?

It's one of these things that seem a really good idea if you are a teacher and never had to write and maintain any code for a living. I love seeing code where (1) I know what it does; and, (2) I'm confident that the person writing it knew what it does.

堇年纸鸢 2024-08-12 11:25:14

这一切都是为了管理复杂性。使用命名空间会引入您不想要的东西,因此可能会使调试变得更加困难(我说可能)。到处使用 std:: 更难阅读(更多文本等等)。

课程马匹 - 以您最好的方式和感觉能够管理您的复杂性。

It's all about managing complexity. Using the namespace will pull things in that you don't want, and thus possibly make it harder to debug (I say possibly). Using std:: all over the place is harder to read (more text and all that).

Horses for courses - manage your complexity how you best can and feel able.

满身野味 2024-08-12 11:25:14

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


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

class stringstream {  // Uh oh
};

注意,这是一个简单的示例。如果您的文件包含 20 个包含项和其他导入项,那么您将需要检查大量依赖项才能找出问题。更糟糕的是,根据冲突的定义,您可能会在其他模块中遇到不相关的错误。

这并不可怕,但是如果不在头文件或全局命名空间中使用它,您会省去很多麻烦。在非常有限的范围内执行此操作可能没问题,但我在输入额外的五个字符来澄清我的函数来自何处时从未遇到过问题。

Consider

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


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

class stringstream {  // Uh oh
};

Note that this is a simple example. If you have files with 20 includes and other imports, you'll have a ton of dependencies to go through to figure out the problem. The worse thing about it is that you can get unrelated errors in other modules depending on the definitions that conflict.

It's not horrible, but you'll save yourself headaches by not using it in header files or the global namespace. It's probably all right to do it in very limited scopes, but I've never had a problem typing the extra five characters to clarify where my functions are coming from.

深海少女心 2024-08-12 11:25:14

一个具体的例子来澄清这个问题。想象一下,您有两个库: foobar,每个库都有自己的命名空间:

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

namespace bar {
    ...
}

现在假设您使用 foo 和 < code>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 (由于该命名空间中的事物数量)。

最终,这是可写性与可靠性/可维护性之间的权衡。可读性也可能是一个因素,但我可以看到无论哪种方式的争论。通常我会说可靠性和可维护性更重要,但在这种情况下,您将不断为相当罕见的可靠性/可维护性影响付出可写性成本。 “最佳”权衡将取决于您的项目和优先事项。

A concrete example to clarify the concern. Imagine you have a situation where you have two libraries, foo and bar, each with their own namespace:

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

namespace bar {
    ...
}

Now let's say you use foo and bar together in your own program as follows:

using namespace foo;
using namespace bar;

void main() {
    a(42);
}

At this point everything is fine. When you run your program it 'Does something'. But later you update bar and let's say it has changed to be like:

namespace bar {
    void a(float) { /* Does something completely different */ }
}

At this point you'll get a compiler error:

using namespace foo;
using namespace bar;

void main() {
    a(42);  // error: call to 'a' is ambiguous, should be foo::a(42)
}

So you'll need to do some maintenance to clarify that 'a' meant foo::a. That's undesirable, but fortunately it is pretty easy (just add foo:: in front of all calls to a that the compiler marks as ambiguous).

But imagine an alternative scenario where bar changed instead to look like this instead:

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

At this point your call to a(42) suddenly binds to bar::a instead of foo::a and instead of doing 'something' it does 'something completely different'. No compiler warning or anything. Your program just silently starts doing something completely different than before.

When you use a namespace you're risking a scenario like this, which is why people are uncomfortable using namespaces. The more things in a namespace, the greater the risk of conflict, so people might be even more uncomfortable using namespace std (due to the number of things in that namespace) than other namespaces.

Ultimately this is a trade-off between writability vs. reliability/maintainability. Readability may factor in also, but I could see arguments for that going either way. Normally I would say reliability and maintainability are more important, but in this case you'll constantly pay the writability cost for an fairly rare reliability/maintainability impact. The 'best' trade-off will determine on your project and your priorities.

橘虞初梦 2024-08-12 11:25:14
  1. 您需要能够阅读由与您有不同风格和最佳实践观点的人编写的代码。

  2. 如果您只使用cout,没有人会感到困惑。但是,当您有很多命名空间,并且您看到此类并且不确定它的作用时,显式命名空间将充当某种注释。乍一看,您可以看到“哦,这是一个文件系统操作”或“这是一个网络操作”。

  1. You need to be able to read code written by people who have different style and best practices opinions than you.

  2. If you're only using cout, nobody gets confused. But when you have lots of namespaces flying around and you see this class and you aren't exactly sure what it does, having the namespace explicit acts as a comment of sorts. You can see at first glance, "oh, this is a filesystem operation" or "that's doing network stuff".

铁憨憨 2024-08-12 11:25:14

同时使用许多命名空间显然会导致灾难,但在我看来,仅使用命名空间 std 并且仅使用命名空间 std 并不是什么大问题,因为重新定义可以仅由您自己的代码发生...

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

人们不应该再对此如此耿耿于怀。你的老师一直都是对的。只使用一个命名空间;这就是首先使用名称空间的全部意义。您不应该同时使用多个。除非是你自己的。因此,重新定义不会发生。

Using many namespaces at the same time is obviously a recipe for disaster, but using JUST namespace std and only namespace std is not that big of a deal in my opinion because redefinition can only occur by your own code...

So just consider them functions as reserved names like "int" or "class" and that is it.

People should stop being so anal about it. Your teacher was right all along. Just use ONE namespace; that is the whole point of using namespaces the first place. You are not supposed to use more than one at the same time. Unless it is your own. So again, redefinition will not happen.

小姐丶请自重 2024-08-12 11:25:14

我同意这里其他人的观点,但我想解决有关可读性的问题 - 您可以通过简单地在文件、函数或类声明的顶部使用 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;
}

I agree with the others here, but I would like to address the concerns regarding readability - you can avoid all of that by simply using typedefs at the top of your file, function or class declaration.

I usually use it in my class declaration as methods in a class tend to deal with similar data types (the members) and a typedef is an opportunity to assign a name that is meaningful in the context of the class. This actually aids readability in the definitions of the class methods.

// Header
class File
{
   typedef std::vector<std::string> Lines;
   Lines ReadLines();
}

and in the implementation:

// .cpp
Lines File::ReadLines()
{
    Lines lines;
    // Get them...
    return lines;
}

as opposed to:

// .cpp
vector<string> File::ReadLines()
{
    vector<string> lines;
    // Get them...
    return lines;
}

or:

// .cpp
std::vector<std::string> File::ReadLines()
{
    std::vector<std::string> lines;
    // Get them...
    return lines;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文