Using std Namespace

前端 未结 16 714
佛祖请我去吃肉
佛祖请我去吃肉 2020-11-22 04:57

There seem to be different views on using \'using\' with respect to the std namespace.

Some say use \' using namespace std\', other say don\'t but rathe

相关标签:
16条回答
  • 2020-11-22 05:11

    First, some terminology:

    • using-declaration: using std::vector;
    • using-directive: using namespace std;

    I think that using using-directives are fine, as long as they aren't used at the global scope in a header file. So having

    using namespace std;
    

    in your .cpp file isn't really a problem, and if it turns out to be, it's completely under your control (and it can even be scoped to particular blocks if desired). I see no particlar reason to clutter up the code with a slew of std:: qualifiers - it just becomes a bunch of visual noise. However, if you're not using a whole bunch of names from the std namespace in your code, I also see no problem with leaving out the directive. It's a tautology - if the directive isn't necessary, then there's no need to use it.

    Similarly, if you can get by with a few using-declarations (instead of using-directives) for specfic types in the std namespace, then there's no reason you shouldn't have just those spefcific names brought into the current namespace. By the same token, I think it would be crazy and a bookkeeping hassle to have 25 or 30 using-declarations when a single using-directive would do the trick just as well.

    It's also good to keep in mind that there are times when you must use a using-declaration. Refer to Scott Meyers' "Item 25: Consider support for a non-throwing swap" from Effective C++, Third Edition. In order to have a generic, templated function use the 'best' swap method for a parameterized type, you need to make use of a using-declaration and argument dependant lookup (aka ADL or Koenig lookup):

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

    I think we should look at the common idioms for various languages that make significant use of namespaces. For example, Java and C# use namespaces to a large extent (arguably moreso than C++). The most common way names within namespaces are used in those languages is by bringing them into the current scope en masse with the equivalent of a using-directive. This doesn't cause wide-spread problems, and the few times it is a problem are handled on an 'exception' basis by dealing with the names in question via fully-qualified names or by aliasing - just like can be done in C++.

    Herb Sutter and Andrei Alexandrescu have this to say in "Item 59: Don't write namespace usings in a header file or before an #include" of their book, C++ Coding Standards: 101 Rules, Guidelines, and Best Practices:

    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.

    Stroupstrup is often quoted as saying, "Don’t pollute the global namespace", in "The C++ Programming Language, Third Edition". He does in fact say that (C.14[15]), but refers to chapter C.10.1 where he says:

    A using-declaration adds a name to a local scope. A using-directive does not; it simply renders names accessible in the scope in which they were declared. For example:

    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
    }
    

    A locally declared name (declared either by an ordinary declaration or by a using-declaration) hides nonlocal declarations of the same name, and any illegal overloadings of the name are detected at the point of declaration.

    Note the ambiguity error for k++ in f1(). Global names are not given preference over names from namespaces made accessible in the global scope. This provides significant protection against accidental name clashes, and – importantly – ensures that there are no advantages to be gained from polluting the global namespace.

    When libraries declaring many names are made accessible through using-directives, it is a significant advantage that clashes of unused names are not considered errors.

    ...

    I hope to see a radical decrease in the use of global names in new programs using namespaces compared to traditional C and C++ programs. The rules for namespaces were specifically crafted to give no advantages to a ‘‘lazy’’ user of global names over someone who takes care not to pollute the global scope.

    And how does one have the same advantage as a 'lazy user of global names'? By taking advantage of the using-directive, which safely makes names in a namespace available to the current scope.

    Note that there's a distinction - names in the std namespace made available to a scope with the proper use of a using-directive (by placing the directive after the #includes) does not pollute the global namespace. It's just making those names available easily, and with continued protection against clashes.

    0 讨论(0)
  • 2020-11-22 05:11

    Why not for example

    typedef std::vector<int> ints_t;
    ints_t ints1;
    ....
    ints_t ints2;
    

    instead of the unwieldy

    std::vector<int> ints1;
    ...
    std::vector<int> ints2;
    

    I find that much more readable and its my standard for coding.

    You can even use it to include some semantic information for the reader. For example, consider the function prototypes

    void getHistorgram(std::vector<unsigned int>&, std::vector<unsigned int>&);
    

    which ones the return value?

    How about instead

    typedef std::vector<unsigned int> values_t;
    typedef std::vector<unsigned int> histogram_t;
    ...
    void getHistogram(values_t&, histogram_t&); 
    
    0 讨论(0)
  • 2020-11-22 05:14

    What are the pros and cons of each

    The only reason to leave off the std:: is that you could, in theory, reimplement all the STL functions yourself. Then your functions could be switched from using std::vector to my::vector without changing the code.

    0 讨论(0)
  • 2020-11-22 05:17

    Most C++ users are quite happy reading std::string, std::vector, etc. In fact, seeing a raw vector makes me wonder if this is the std::vector or a different user-defined vector.

    I am always against using using namespace std;. It imports all sorts of names into the global namespace and can cause all sorts of non-obvious ambiguities.

    Here are some common identifiers that are in the std namespace: count, sort, find, equal, reverse. Having a local variable called count means that using namespace std won't enable you to use count instead of std::count.

    The classic example of an unwanted name conflict is something like the following. Imagine that you are a beginner and don't know about std::count. Imagine that you are either using something else in <algorithm> or it's been pulled in by a seemingly unrelated header.

    #include <algorithm>
    using namespace std;
    
    int count = 0;
    
    int increment()
    {
        return ++count; // error, identifier count is ambiguous
    }
    

    The error is typically long and unfriendly because std::count is a template with some long nested types.

    This is OK though, because std::count goes into the global namespace and the function count hides it.

    #include <algorithm>
    using namespace std;
    
    int increment()
    {
        static int count = 0;
        return ++count;
    }
    

    Perhaps slightly surprisingly, this is OK. Identifiers imported into a declarative scope appear in the common namespace that encloses both where they are defined and where they are imported into. In other words, std::count is visible as count in the global namespace, but only inside increment.

    #include <algorithm>
    
    int increment()
    {
        using namespace std;
        static int count = 0;
        return ++count;
    }
    

    And for similar reasons, count is ambiguous here. using namespace std doesn't cause std::count, hide the outer count as it might be expected. The using namespace rule means that std::count looks (in the increment function) as though it was declared at the global scope, i.e. at the same scope as int count = 0; and hence causing the ambiguity.

    #include <algorithm>
    
    int count = 0;
    
    int increment()
    {
        using namespace std;
        return ++count; // error ambiguous
    }
    
    0 讨论(0)
  • 2020-11-22 05:19

    For me, I prefer to use :: when possible.

    std::list<int> iList;
    

    I hate to write :

    for(std::list<int>::iterator i = iList.begin(); i != iList.end(); i++)
    {
        //
    }
    

    Hopefully, with C++0x I would write this:

    for(auto i = iList.begin(); i != iList.end(); i++)
    {
        //
    }
    

    If the namespace is very lengthy,

    namespace dir = boost::filesystem;
    
    dir::directory_iterator file("e:/boost");
    dir::directory_iterator end;
    
    for( ; file != end; file++)
    {
        if(dir::is_directory(*file))
            std::cout << *file << std::endl;
    }
    
    0 讨论(0)
  • 2020-11-22 05:20

    Namespaces keep code contained to prevent confusion and pollution of function signatures.

    Here's a complete and documented demo of proper namespace usage:

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

    Output:

    Our log: 42
    Standard log: 1.43508
    
    0 讨论(0)
提交回复
热议问题