Unnamed/anonymous namespaces vs. static functions

后端 未结 11 1943
一个人的身影
一个人的身影 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 04:10

    Use of static keyword for that purpose is deprecated by the C++98 standard. The problem with static is that it doesn't apply to type definition. It's also an overloaded keyword used in different ways in different contexts, so unnamed namespaces simplify things a bit.

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

    The difference is the name of the mangled identifier (_ZN12_GLOBAL__N_11bE vs _ZL1b , which doesn't really matter, but both of them are assembled to local symbols in the symbol table (absence of .global asm directive).

    #include<iostream>
    namespace {
       int a = 3;
    }
    
    static int b = 4;
    int c = 5;
    
    int main (){
        std::cout << a << b << c;
    }
    
            .data
            .align 4
            .type   _ZN12_GLOBAL__N_11aE, @object
            .size   _ZN12_GLOBAL__N_11aE, 4
    _ZN12_GLOBAL__N_11aE:
            .long   3
            .align 4
            .type   _ZL1b, @object
            .size   _ZL1b, 4
    _ZL1b:
            .long   4
            .globl  c
            .align 4
            .type   c, @object
            .size   c, 4
    c:
            .long   5
            .text
    

    As for a nested anonymous namespace:

    namespace {
       namespace {
           int a = 3;
        }
    }
    
            .data
            .align 4
            .type   _ZN12_GLOBAL__N_112_GLOBAL__N_11aE, @object
            .size   _ZN12_GLOBAL__N_112_GLOBAL__N_11aE, 4
    _ZN12_GLOBAL__N_112_GLOBAL__N_11aE:
            .long   3
    

    All 1st level anonymous namespaces in the translation unit are combined with each other, All 2nd level nested anonymous namespaces in the translation unit are combined with each other

    You can also have a nested namespace or nested inline namespace in an anonymous namespace

    namespace {
       namespace A {
           int a = 3;
        }
    }
    
            .data
            .align 4
            .type   _ZN12_GLOBAL__N_11A1aE, @object
            .size   _ZN12_GLOBAL__N_11A1aE, 4
    _ZN12_GLOBAL__N_11A1aE:
            .long   3
    
    which for the record demangles as:
            .data
            .align 4
            .type   (anonymous namespace)::A::a, @object
            .size   (anonymous namespace)::A::a, 4
    (anonymous namespace)::A::a:
            .long   3
    
    //inline has the same output
    

    You can also have anonymous inline namespaces, but as far as I can tell, inline on an anonymous namespace has 0 effect

    inline namespace {
       inline namespace {
           int a = 3;
        }
    }
    

    _ZL1b: _Z means this is a mangled identifier. L means it is a local symbol through static. 1 is the length of the identifier b and then the identifier b

    _ZN12_GLOBAL__N_11aE _Z means this is a mangled identifier. N means this is a namespace 12 is the length of the anonymous namespace name _GLOBAL__N_1, then the anonymous namespace name _GLOBAL__N_1, then 1 is the length of the identifier a, a is the identifier a and E closes the identifier that resides in a namespace.

    _ZN12_GLOBAL__N_11A1aE is the same as above except there's another namespace level in it 1A

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

    The C++ Standard reads in section 7.3.1.1 Unnamed namespaces, paragraph 2:

    The use of the static keyword is deprecated when declaring objects in a namespace scope, the unnamed-namespace provides a superior alternative.

    Static only applies to names of objects, functions, and anonymous unions, not to type declarations.

    Edit:

    The decision to deprecate this use of the static keyword (affecting visibility of a variable declaration in a translation unit) has been reversed (ref). In this case using a static or an unnamed namespace are back to being essentially two ways of doing the exact same thing. For more discussion please see this SO question.

    Unnamed namespace's still have the advantage of allowing you to define translation-unit-local types. Please see this SO question for more details.

    Credit goes to Mike Percy for bringing this to my attention.

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

    I recently began replacing static keywords with anonymous namespaces in my code but immediately ran into a problem where the variables in the namespace were no longer available for inspection in my debugger. I was using VC60, so I don't know if that is a non-issue with other debuggers. My workaround was to define a 'module' namespace, where I gave it the name of my cpp file.

    For example, in my XmlUtil.cpp file, I define a namespace XmlUtil_I { ... } for all of my module variables and functions. That way I can apply the XmlUtil_I:: qualification in the debugger to access the variables. In this case, the _I distinguishes it from a public namespace such as XmlUtil that I may want to use elsewhere.

    I suppose a potential disadvantage of this approach compared to a truly anonymous one is that someone could violate the desired static scope by using the namespace qualifier in other modules. I don't know if that is a major concern though.

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

    In addition if one uses static keyword on a variable like this example:

    namespace {
       static int flag;
    }
    

    It would not be seen in the mapping file

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