代码之家  ›  专栏  ›  技术社区  ›  Scottie T

为什么要使用未命名的命名空间,它们的好处是什么?

  •  196
  • Scottie T  · 技术社区  · 16 年前

    我刚刚加入了一个新的C++软件项目,我正在尝试理解这个设计。该项目经常使用未命名的命名空间。例如,类定义文件中可能会出现这样的情况:

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

    可能导致使用未命名命名空间的设计注意事项是什么?有哪些优点和缺点?

    6 回复  |  直到 6 年前
        1
  •  166
  •   Michael Geary    6 年前

    (以下为 打穿 事情是不再适用于C++ 11的东西,而是应用于C++ 03。C++ 11几乎没有任何区别(如果有的话,它们只是语言律师的差异,我不记得了)。

    未命名的命名空间是一个用于生成标识符的实用程序 有效地 本地翻译单元。它们的行为就好像您要为名称空间的每个翻译单元选择一个唯一的名称:

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

    使用空主体的额外步骤很重要,因此您可以在命名空间主体内引用类似的标识符 ::name 在该命名空间中定义的,因为已经发生了using指令。

    这意味着您可以调用自由函数(例如) help 它可以存在于多个翻译单元中,并且不会在链接时发生冲突, 因为它们都有一个唯一的名称空间,所以它们都在 . 效果几乎与使用 static 在C中使用的关键字,可以将其放入标识符声明中。 静止的 用这种方式在C++中被弃用,因为 未命名的名称空间是一种更好的选择,甚至能够使类型转换单元成为本地的。

    namespace { int a1; }
    static int a2;
    

    两个 a 的是本地翻译单元,不会在链接时发生冲突。但区别在于 a1 在匿名命名空间中 只是 获取唯一的名称。 它仍然具有外部链接,可以导出到正在创建的对象文件的符号表中。如果要将其地址用作模板参数,则这一点很重要:

    template<int * ptr> struct sample { };
    
    // OK - a1 has external linkage
    sample<&a1> s1; 
    // NOT OK - translation unit locality is done by giving a2 internal linkage. 
    sample<&a2> s2; 
    

    模板参数必须具有外部链接,因此在这种情况下,必须将标识符放入匿名命名空间。

    阅读Comeau计算公司的优秀文章 Why is an unnamed namespace used instead of static? ( Archive.org mirror )

        2
  •  57
  •   N0thing    8 年前

    在匿名名称空间中拥有某些内容意味着它是本地的 translation unit (.cpp文件及其所有包含项)这意味着如果在其他地方定义了具有相同名称的其他符号,则不会违反 One Definition Rule (ODR)。

    这与使用静态全局变量或静态函数的C方法相同,但也可以用于类定义(应该使用而不是 static 在C++中。

    同一文件中的所有匿名命名空间都被视为同一命名空间,不同文件中的所有匿名命名空间都是不同的。匿名命名空间等效于:

    namespace __unique_compiler_generated_identifer0x42 {
        ...
    }
    using namespace __unique_compiler_generated_identifer0x42;
    
        3
  •  12
  •   Marc Mutz - mmutz    15 年前

    示例显示,您加入的项目中的人员不了解匿名命名空间:)

    namespace {
        const int SIZE_OF_ARRAY_X;
        const int SIZE_OF_ARRAY_Y;
    

    这些不需要在匿名命名空间中,因为 const 对象已经有静态链接,因此不能与另一个翻译单元中同名的标识符冲突。

        bool getState(userType*,otherUserType*);
    }
    

    这实际上是一种悲观情绪: getState() 具有外部链接。通常最好选择静态链接,因为这样不会污染符号表。最好是写

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

    在这里。我掉进了同一个陷阱(标准中的措辞表明文件静力学在某种程度上被贬低为匿名的命名空间),但是在像KDE这样的大型C++项目中,你会得到很多人再次正确地改变你的方向:

        4
  •  12
  •   xioxox    10 年前

    除了这个问题的其他答案外,使用匿名名称空间还可以提高性能。由于名称空间中的符号不需要任何外部链接,编译器可以更自由地对名称空间中的代码执行积极的优化。例如,一个循环中多次调用的函数可以被内联,而不会对代码大小产生任何影响。

    例如,在我的系统上,如果使用匿名命名空间,以下代码将占用大约70%的运行时间(x86-64 gcc-4.6.3和-o2;请注意,add-val中的额外代码使编译器不希望将其包括两次)。

    #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;
    }
    
        5
  •  9
  •   Max Lybbert    16 年前

    匿名名称空间使封闭的变量、函数、类等仅在该文件中可用。在您的示例中,这是一种避免全局变量的方法。没有运行时或编译时性能差异。

    除了“我希望这个变量、函数、类等是公共的还是私有的?”之外,没有什么优势或劣势。

        6
  •  6
  •   Community CDub    7 年前

    未命名的命名空间将类、变量、函数和对象的访问权限限制在定义它的文件中。未命名的命名空间功能类似于 static 关键字在C/C++中。
    静止的 关键字限制对定义全局变量和函数的文件的访问。
    未命名的命名空间和 静止的 关键字,因此未命名命名空间优于静态命名空间。 静止的 关键字可以用于变量、函数和对象,但不能用于用户定义的类。
    例如:

    static int x;  // Correct 
    

    但是,

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

    但对于未命名的命名空间也可以这样。 例如,

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