Unnamed/anonymous namespaces vs. static functions

后端 未结 11 1942
一个人的身影
一个人的身影 2020-11-22 03:27

A feature of C++ is the ability to create unnamed (anonymous) namespaces, like so:

namespace {
    int cannotAccessOutsideThisFile() { ... }
} // namespace
<         


        
相关标签:
11条回答
  • 2020-11-22 03:58

    Personally I prefer static functions over nameless namespaces for the following reasons:

    • It's obvious and clear from function definition alone that it's private to the translation unit where it's compiled. With nameless namespace you might need to scroll and search to see if a function is in a namespace.

    • Functions in namespaces might be treated as extern by some (older) compilers. In VS2017 they are still extern. For this reason even if a function is in nameless namespace you might still want to mark them static.

    • Static functions behave very similar in C or C++, while nameless namespaces are obviously C++ only. nameless namespaces also add extra level in indentation and I don't like that :)

    So, I'm happy to see that use of static for functions isn't deprecated anymore.

    0 讨论(0)
  • 2020-11-22 03:58

    A compiler specific difference between anonymous namespaces and static functions can be seen compiling the following code.

    #include <iostream>
    
    namespace
    {
        void unreferenced()
        {
            std::cout << "Unreferenced";
        }
    
        void referenced()
        {
            std::cout << "Referenced";
        }
    }
    
    static void static_unreferenced()
    {
        std::cout << "Unreferenced";
    }
    
    static void static_referenced()
    {
        std::cout << "Referenced";
    }
    
    int main()
    {
        referenced();
        static_referenced();
        return 0;
    }
    

    Compiling this code with VS 2017 (specifying the level 4 warning flag /W4 to enable warning C4505: unreferenced local function has been removed) and gcc 4.9 with the -Wunused-function or -Wall flag shows that VS 2017 will only produce a warning for the unused static function. gcc 4.9 and higher, as well as clang 3.3 and higher, will produce warnings for the unreferenced function in the namespace and also a warning for the unused static function.

    Live demo of gcc 4.9 and MSVC 2017

    0 讨论(0)
  • 2020-11-22 03:59

    Putting methods in an anonymous namespace prevents you from accidentally violating the One Definition Rule, allowing you to never worry about naming your helper methods the same as some other method you may link in.

    And, as pointed out by luke, anonymous namespaces are preferred by the standard over static members.

    0 讨论(0)
  • 2020-11-22 04:02

    From experience I'll just note that while it is the C++ way to put formerly-static functions into the anonymous namespace, older compilers can sometimes have problems with this. I currently work with a few compilers for our target platforms, and the more modern Linux compiler is fine with placing functions into the anonymous namespace.

    But an older compiler running on Solaris, which we are wed to until an unspecified future release, will sometimes accept it, and other times flag it as an error. The error is not what worries me, it's what it might be doing when it accepts it. So until we go modern across the board, we are still using static (usually class-scoped) functions where we'd prefer the anonymous namespace.

    0 讨论(0)
  • 2020-11-22 04:08

    There is one edge case where static has a surprising effect(at least it was to me). The C++03 Standard states in 14.6.4.2/1:

    For a function call that depends on a template parameter, if the function name is an unqualified-id but not a template-id, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2) except that:

    • For the part of the lookup using unqualified name lookup (3.4.1), only function declarations with external linkage from the template definition context are found.
    • For the part of the lookup using associated namespaces (3.4.2), only function declarations with external linkage found in either the template definition context or the template instantiation context are found.

    ...

    The below code will call foo(void*) and not foo(S const &) as you might expect.

    template <typename T>
    int b1 (T const & t)
    {
      foo(t);
    }
    
    namespace NS
    {
      namespace
      {
        struct S
        {
        public:
          operator void * () const;
        };
    
        void foo (void*);
        static void foo (S const &);   // Not considered 14.6.4.2(b1)
      }
    
    }
    
    void b2()
    {
      NS::S s;
      b1 (s);
    }
    

    In itself this is probably not that big a deal, but it does highlight that for a fully compliant C++ compiler (i.e. one with support for export) the static keyword will still have functionality that is not available in any other way.

    // bar.h
    export template <typename T>
    int b1 (T const & t);
    
    // bar.cc
    #include "bar.h"
    template <typename T>
    int b1 (T const & t)
    {
      foo(t);
    }
    
    // foo.cc
    #include "bar.h"
    namespace NS
    {
      namespace
      {
        struct S
        {
        };
    
        void foo (S const & s);  // Will be found by different TU 'bar.cc'
      }
    }
    
    void b2()
    {
      NS::S s;
      b1 (s);
    }
    

    The only way to ensure that the function in our unnamed namespace will not be found in templates using ADL is to make it static.

    Update for Modern C++

    As of C++ '11, members of an unnamed namespace have internal linkage implicitly (3.5/4):

    An unnamed namespace or a namespace declared directly or indirectly within an unnamed namespace has internal linkage.

    But at the same time, 14.6.4.2/1 was updated to remove mention of linkage (this taken from C++ '14):

    For a function call where the postfix-expression is a dependent name, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2) except that:

    • For the part of the lookup using unqualified name lookup (3.4.1), only function declarations from the template definition context are found.

    • For the part of the lookup using associated namespaces (3.4.2), only function declarations found in either the template definition context or the template instantiation context are found.

    The result is that this particular difference between static and unnamed namespace members no longer exists.

    0 讨论(0)
  • 2020-11-22 04:08

    Having learned of this feature only just now while reading your question, I can only speculate. This seems to provide several advantages over a file-level static variable:

    • Anonymous namespaces can be nested within one another, providing multiple levels of protection from which symbols can not escape.
    • Several anonymous namespaces could be placed in the same source file, creating in effect different static-level scopes within the same file.

    I'd be interested in learning if anyone has used anonymous namespaces in real code.

    0 讨论(0)
提交回复
热议问题