未命名/匿名命名空间与静态函数

新手上路,请多包涵

C++ 的一个特性是能够创建未命名(匿名)命名空间,如下所示:

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

你会认为这样的特性是没有用的——因为你不能指定命名空间的名称,所以不可能从外部访问其中的任何内容。但是这些未命名 的命名空间可以在创建它们的文件中 访问,就好像你对它们有一个隐含的 using 子句一样。

我的问题是,为什么或什么时候这比使用静态函数更可取?或者他们本质上是做同样事情的两种方式?

原文由 Head Geek 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 980
2 个回答

C++ 标准在第 7.3.1.1 节未命名命名空间,第 2 段中写道:

在命名空间范围内声明对象时,不推荐使用 static 关键字,未命名命名空间提供了更好的选择。

静态仅适用于对象、函数和匿名联合的名称,不适用于类型声明。

编辑:

弃用 static 关键字(影响翻译单元中变量声明的可见性)的决定已被撤销( ref )。在这种情况下,使用 static 或未命名的 namespace 基本上是两种做同样事情的方法。有关更多讨论,请参阅 SO question。

未命名的 namespace 仍然具有允许您定义翻译单元本地类型的优势。有关更多详细信息,请参阅 SO 问题。

感谢 Mike Percy 让我注意到了这一点。

原文由 luke 发布,翻译遵循 CC BY-SA 4.0 许可协议

不同之处在于损坏标识符的名称( _ZN12_GLOBAL__N_11bE vs _ZL1b ,这并不重要,但它们都被组装成符号表中的本地符号(没有 .global asm 指令)。

 #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

至于嵌套的匿名命名空间:

 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

翻译单元中的所有 1 级匿名命名空间相互组合,翻译单元中的所有 2 级嵌套匿名命名空间相互组合

您还可以在匿名命名空间中拥有嵌套命名空间或嵌套内联命名空间

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

您也可以使用匿名内联命名空间,但据我所知,匿名命名空间上的 inline 效果为 0

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

_ZL1b : _Z 表示这是一个损坏的标识符。 L 表示它是通过 static 的本地符号。 1 是标识符 b 的长度,然后是标识符 b

_ZN12_GLOBAL__N_11aE _Z 表示这是一个损坏的标识符。 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在命名空间中。

_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.匿名命名空间都有名字 _GLOBAL__N_1

原文由 Lewis Kelsey 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题