ChatGPT解决这个技术问题 Extra ChatGPT

Unnamed/anonymous namespaces vs. static functions

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

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

You would think that such a feature would be useless -- since you can't specify the name of the namespace, it's impossible to access anything within it from outside. But these unnamed namespaces are accessible within the file they're created in, as if you had an implicit using-clause to them.

My question is, why or when would this be preferable to using static functions? Or are they essentially two ways of doing the exact same thing?

In C++11 the usage of static in this context was undeprecated; although unnamed namespace is a superior alternative to static, there're instances where it fails when static comes to the rescue.

O
Olivia Stork

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.


Head Geek asks about static keyword used against functions only. The static keyword applied to entity declared in namespace scope specifies its internal linkage. Entity declared in anonymous namespace has external linkage (C++/3.5) however it is guaranteed to live in uniquely named scope. This anonymity of unnamed namespace effectively hides its declaration making it accessible only from within a translation unit. The latter effectively works in the same manner as the static keyword.
what is the drawback of external linkage? Could this affect inlining?
Those at the C++ design comitee who said static keyword is deprecated probably never worked with a huge C code in a large real world system... (You immedaiately see a static keyword but not the anonymous namespace if it contains lot of declarations with large comment blocks.)
Because this answer comes up on Google as a top result for "c++ anonymous namespace", it should be noted that the use of static is no longer deprecated. See stackoverflow.com/questions/4726570/… and open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1012 for more information.
@ErikAronesty That sounds wrong. Do you have a reproducible example? As of C++11 - and even before that in some compilers - unnamed namespaces implicitly have internal linkage, so there should be no difference. Any issues that might previously have arisen from poor wording were resolved by making this a requirement in C++11.
G
Gulzar

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.


I was referring to static stand-alone functions (i.e. file-scoped functions), not static member functions. Static stand-alone functions are much the same as functions in an unnamed namespace, thus the question.
Ah; well, the ODR still applies. Edited to remove paragraph.
as I get, ODR for a static function doesn't work when it's defined in header and this header is included into more than one translation unit, right? in this case you receive multiple copies of the same function
@Andy T: You don't really see the "multiple definitions" in case of included header. Preprocessor takes care of it. Unless there is a need in studying the output that preprocessor has generated, which to me looks rather exotic and rare. Also there is a good practice to include "guards" in header files, like: "#ifndef SOME_GUARD - #define SOME_GUARD ..." which is supposed to prevent preprocessor from including same header twice.
@NikitaVorontsov the guard may prevent including the same header into the same translation unit, however it allows multiple definitions in different translation units. This might cause "multiple definitions" linker error down the line.
M
Moshe Slavin

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.


Isn't the export keyword supposed to be cold dead? The only compilers supporting "export" are experimental ones, and unless surprises, "export" won't even be implemented in others because of unexpected side effects (in addition to not doing was it was expected for)
See Herb Sutter's article on the subjet: gotw.ca/publications/mill23-x.htm
The front-end from Edison Design Group (EDG) is anything but experimental. It is almost certainly the most standard conforming C++ implementation in the world. The Intel C++ compiler uses EDG.
What C++ feature doesn't have 'unexpected side-effects'? In the case of export, it is that an unnamed namespace function will be found from a different TU - that is the same as if you included the template definition directly. It would be more surprising if it was not like this!
I think you have a typo there - for NS::S to work, doesn't S need to not be inside namespace {}?
E
Evg

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.


I've done this too, but with #if DEBUG namespace BlahBlah_private { #else namespace { #endif, so the "module namespace" is only present in debug builds and true anonymous namespace is used otherwise. It would be nice if debuggers gave a nice way to handle this. Doxygen gets confused by it also.
unnamed namespace is not really a viable replacement for static. static means "really this never gets linked ouside of the TU". unnamed namespace means "it's still exported, as a random name, in case it gets called from a parent class that is outside the TU"...
R
RobertS supports Monica Cellio

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.


Functions in anonymous namespaces are supposed to have external linkage. They're just mangled to make them unique. Only the static keyword actually applies local linkage to a function. Also, surely only a raving lunatic would actually add indentation for namespaces?
@Roflcopter4 many editors by default add indent for namespaces.
Major one for me is trying to debug. Nameless namespaces aren't nameless once compiled, they just get an untypeable auto-generated name.
F
Firas Assaad

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.


If you want to use a type only in a single translation unit then declare it inside the .cpp file. It won't be accessible from other translation units anyway.
You'd think, wouldn't you? But if another translation unit(=cpp-file) in the same application ever declares a type with the same name, you're in for rather hard-to-debug problems :-). For example, you may end up with situations where the vtable for one of the types is used when calling methods on the other.
Not deprecated anymore. And type defs aren't exported, so that's meaningless. statics are useful for standalone functions and global vars. unnamed namespaces are useful for classes.
D
Don Wakefield

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.


L
Lewis Kelsey

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 (1A) in it called A, prefixed with the length of A which is 1. Anonymous namespaces all have the name _GLOBAL__N_1


C
Chris

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


Then you don't need anonymous namespace at all.
m
masrtis

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


C
Commodore Jaeger

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.


Good speculations, but wrong. The scope of these namespaces is file-wide.
Not exactly true, if you define an anonymous namespace inside another namespace it is still only file wide, and can only be seen as being within that namespace. Try it.
I could be wrong but, I guess that no, it is not file-wide: It is accessible only to the code after the anonymous namespace. This is a subtle thingy, and usually, I would not want to pollute a source with multiple anonymous namespaces... Still, this can have uses.

关注公众号,不定期副业成功案例分享
Follow WeChat

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now