ChatGPT解决这个技术问题 Extra ChatGPT

Why are unnamed namespaces used and what are their benefits?

I just joined a new C++ software project and I'm trying to understand the design. The project makes frequent use of unnamed namespaces. For example, something like this may occur in a class definition file:

// newusertype.cc
namespace {
  const int SIZE_OF_ARRAY_X;
  const int SIZE_OF_ARRAY_Y;
  bool getState(userType*,otherUserType*);
}

newusertype::newusertype(...) {...

What are the design considerations that might cause one to use an unnamed namespace? What are the advantages and disadvantages?


b
bobobobo

Unnamed namespaces are a utility to make an identifier translation unit local. They behave as if you would choose a unique name per translation unit for a namespace:

namespace unique { /* empty */ }
using namespace unique;
namespace unique { /* namespace body. stuff in here */ }

The extra step using the empty body is important, so you can already refer within the namespace body to identifiers like ::name that are defined in that namespace, since the using directive already took place.

This means you can have free functions called (for example) help that can exist in multiple translation units, and they won't clash at link time. The effect is almost identical to using the static keyword used in C which you can put in in the declaration of identifiers. Unnamed namespaces are a superior alternative, being able to even make a type translation unit local.

namespace { int a1; }
static int a2;

Both a's are translation unit local and won't clash at link time. But the difference is that the a1 in the anonymous namespace gets a unique name.

Read the excellent article at comeau-computing Why is an unnamed namespace used instead of static? (Archive.org mirror).


You explain the relation to static. Can you please also compare with __attribute__ ((visibility ("hidden")))?
N
N0thing

Having something in an anonymous namespace means it's local to this translation unit (.cpp file and all its includes) this means that if another symbol with the same name is defined elsewhere there will not be a violation of the One Definition Rule (ODR).

This is the same as the C way of having a static global variable or static function but it can be used for class definitions as well (and should be used rather than static in C++).

All anonymous namespaces in the same file are treated as the same namespace and all anonymous namespaces in different files are distinct. An anonymous namespace is the equivalent of:

namespace __unique_compiler_generated_identifer0x42 {
    ...
}
using namespace __unique_compiler_generated_identifer0x42;

C
Community

Unnamed namespace limits access of class,variable,function and objects to the file in which it is defined. Unnamed namespace functionality is similar to static keyword in C/C++.
static keyword limits access of global variable and function to the file in which they are defined.
There is difference between unnamed namespace and static keyword because of which unnamed namespace has advantage over static. static keyword can be used with variable, function and objects but not with user defined class.
For example:

static int x;  // Correct 

But,

static class xyz {/*Body of class*/} //Wrong
static structure {/*Body of structure*/} //Wrong

But same can be possible with unnamed namespace. For example,

 namespace {
           class xyz {/*Body of class*/}
           static structure {/*Body of structure*/}
  } //Correct

What is static structure? Also why does it have to be static?
@smac89 They probably meant static struct structure.
x
xioxox

In addition to the other answers to this question, using an anonymous namespace can also improve performance. As symbols within the namespace do not need any external linkage, the compiler is freer to perform aggressive optimization of the code within the namespace. For example, a function which is called multiple times once in a loop can be inlined without any impact on the code size.

For example, on my system the following code takes around 70% of the run time if the anonymous namespace is used (x86-64 gcc-4.6.3 and -O2; note that the extra code in add_val makes the compiler not want to include it twice).

#include <iostream>

namespace {
  double a;
  void b(double x)
  {
    a -= x;
  }
  void add_val(double x)
  {
    a += x;
    if(x==0.01) b(0);
    if(x==0.02) b(0.6);
    if(x==0.03) b(-0.1);
    if(x==0.04) b(0.4);
  }
}

int main()
{
  a = 0;
  for(int i=0; i<1000000000; ++i)
    {
      add_val(i*1e-10);
    }
  std::cout << a << '\n';
  return 0;
}

Too good to be true - I tried this segment on gcc 4-1-2, using O3 optimization, with-and-without the namespace statement: -> Got the same time (3sec, with -O3, and 4sec with -O3)
This code was intentionally complex to try to persuade the compiler not to inline b and add_val into main. O3 optimisation uses lots of inlining regardless of the cost to code bloat. There are still, however, likely functions where O3 wouldn't inline add_val. You could try making add_val more complex, or calling it multiple times from main in different circumstances.
@Daniel: what am i missing? as read, you said you compared -O3 to itself, then you said 3 vs 4 seconds are "the same time". neither of these make a bit of sense. i suspect the real explanation would, but what is it?
@underscore_d The answer states -O2 was used in both cases, not -O3. Different optimization levels may behave differently. Also, different compiler versions may behave differently (the answer can get outdated, that is)
@PaulStelian I know that, but it seems pretty clear that I was replying not to xioxox's answer but rather to Theo's comment (albeit either his name has changed or I got mixed up somehow)
M
Marc Mutz - mmutz

The example shows that the people in the project you joined don't understand anonymous namespaces :)

namespace {
    const int SIZE_OF_ARRAY_X;
    const int SIZE_OF_ARRAY_Y;

These don't need to be in an anonymous namespace, since const object already have static linkage and therefore can't possibly conflict with identifiers of the same name in another translation unit.

    bool getState(userType*,otherUserType*);
}

And this is actually a pessimisation: getState() has external linkage. It is usually better to prefer static linkage, as that doesn't pollute the symbol table. It is better to write

static bool getState(/*...*/);

here. I fell into the same trap (there's wording in the standard that suggest that file-statics are somehow deprecated in favour of anonymous namespaces), but working in a large C++ project like KDE, you get lots of people that turn your head the right way around again :)


Since c++11 unnamed namespaces have internal linkage (section 3.5 in the standard or en.cppreference.com/w/cpp/language/namespace#Unnamed_namespaces)
"These don't need to be in an anonymous namespace" Technically, sure - but still, it doesn't hurt to put them in one, as a visual reminder of their semantics and to make it (even more) trivial to remove constness later if desired. I doubt that means the OP's team "don't understand" anything! Also, the bit about functions in anonymous namespaces having external linkage is wrong in C++11 onwards as noted. By my understanding, they fixed an issue of template arguments previously needing external linkage, so could allow unnamed namespaces (able to contain template args) to have internal linkage.
M
Max Lybbert

An anonymous namespace makes the enclosed variables, functions, classes, etc. available only inside that file. In your example it's a way to avoid global variables. There is no runtime or compile time performance difference.

There isn't so much an advantage or disadvantage aside from "do I want this variable, function, class, etc. to be public or private?"


There can be performance differences - see my answer here. It allows the compiler to optimize the code better.
You have a point; at least as far as C++ today is. However, C++98/C++03 required things have external linkage in order to be used as template arguments. Since things in anonymous namespaces are available as template arguments, they would have external linkage (at least in pre-C++11) even if there was no way to refer to them from outside the file. I think there may have been some ability to fudge on that, because the standard only requires that things act as if the rules were enforced; and it's sometimes possible to do that without truly enforcing the rules.