C++ Name Resolution

寵の児 提交于 2020-01-12 07:53:06

问题


I'm wondering a bit about the namespace and using in C++ basically I would like to know the differences and figure out how to use it in the best way.

As I see it there are (at least) three ways to resolve a class name and I am not sure how to choose among them:

  1. using namespace <namespace>
  2. using <namespace>::<what_to_use>
  3. <namespace>::<what_to_use> <use_it>

I would like to know the advantages especially if there are performance involved in one or the other way, if it's just syntactical and a matter of preference or if there are other things I haven't considered regarding this.


回答1:


First is an using namespace directive, it brings all the symbol names from the specified namespace in your current namespace, irrespective of whether you need/use them. Certainly undesirable.

Second is using namespace declaration. It only brings the specified symbol name in your current namespace. Advantage is you don't have to type the fully qualified name everytime.

Third is an fully qualified names of the symbol. Disadvantage is that you have to type the fully qualified name everywhere you use the symbol.

Clearly, Second & Third are the more suitable ones. There is no performance difference in either of them. The only difference is the amount of characters you type in. Simply, choose either depending on what your coding standard specifies.

EDIT:
As @Jerry points out, using declaration in combination with ADL(Argument dependent lookup) can lead to undesirable effects.
You can find a detailed explanation in one of my answers:

Detailed explanation on how Koenig lookup works with namespaces and why its a good thing?

under the section,
Why the criticism of Koenig Algorithm?




回答2:


There is one (admittedly, somewhat uncommon) situation in which the form you use really can make a difference, and the form you want to use is using namespace foo, and it's most commonly applied to the std namespace (i.e., where you write using namespace std;.

The most obvious example is that you're writing a sort for a user-defined type. It's possible that this will be applied to a type for which the user has also defined their own swap.

You're stuck with a situation where you want to use their swap if they've defined one, but use std::swap if they haven't defined one. If you use std::swap directly in your code, then you'll end up using std::swap even if the type has a swap of its own defined. Conversely, your code will fail to compile if you directly specify a swap specifically for the type, and none has been supplied.

To get around this, you do something like:

using namespace std;

template <class Iter>
void my_sort(Iter first, Iter last) {
    // ...
    if (*last < *first)
        swap(*first, *last);
}

This will find the swap specifically for the type being compared (i.e., a swap defined in the same namespace as that type), if there is one (via argument dependent lookup), and std::swap if none is defined for the type (via the using namespace std;).

This can have an impact on performance -- if they've written a swap specifically for their type, you can generally expect that it's because by doing so, they can provide better performance. That means that explicitly specifying std::swap may work, but will probably lead to inferior performance.

Otherwise, it's almost entirely a matter of convenience and readability -- I mostly prefer giving the full names (e.g., std::swap) except in a situation like above, where (at the time that I'm writing the code) either of at least two possibilities might be preferred, and I want to give the compiler sufficient leeway to pick the right one.

The other time I find using declarations/directives useful is when namespaces get really deeply nested. Boost (for one obvious example) has some names that would be way too long for convenient use if you used the fully qualified name every time. This was especially true for the (now, thankfully, mostly obsolete) Boost Lambda library, where you used placeholders like _1, that would have ended up as something like boost::lambda::placeholders::_1 (but I'm going from memory, so that's probably at least partly wrong) if you insisted on using a fully qualified name. That would have defeated a large part of the purpose of using the lambda library in the first place.




回答3:


There's no performance gain or penalty whatsoever. All calls and variables are resolved at compile-time.

The choice between the three is somewhat subjective. Yes, using namespace <ns>; is sometimes frowned upon for polluting the global namespace, but I think it's safe to use for small files.

I tend to use the second one for testing purposes where I'm expecting conflicts, but I'd just remove it afterwards. This can get messier because you can end up with combinations of both qualified and un-qualified names:

vector<std::string> x;

because you have a using std::vector; at the top, but not a using std::string;.

I preffer the third.




回答4:


There is zero impact on performance of your code, this is purely a compile-time thing. It might (in theory) have some impact on compilation times, but I doubt that would ever reach measurable proportions.

using namespace std (or any other namespace for that matter) is definitely to be avoided in header files, which can be included anywhere and introducing the symbols in them could result in ambiguities.

Generally, namespaces exist to avoid name clashes and using namespace destroys this purpose. So does using the_namespace::some_id, to a lesser degree. There is no definite answer to your question, but I generally follow these rules:

  1. Never put using namespace in a header file.
  2. Avoid using namespace and using, unless it can save tremendous amounts of typing. Use namespace aliases if necessary (that is, namespace abbrv = some_really::long_and::nested_namespace;).
  3. Try to limit the scope of using: you can put this into functions and blocks as well as namespace scope. That is, if you have a logging function in your .cpp file, put using std::cout; and using std::endl; (or whatever you're using) into the function body, not into the file scope.



回答5:


Main reason is that it could lead to ambiguities (both for compiler and for human reader) and it can also slowdown the compilation itself (but that's not that big problem as the first thing)



来源:https://stackoverflow.com/questions/14136720/c-name-resolution

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!