【问题标题】:When should I write the keyword 'static' before a non-member function?我什么时候应该在非成员函数之前写关键字'static'?
【发布时间】:2012-01-14 11:04:48
【问题描述】:

我最近在 SO 上看到了一些关于函数前 static 关键字的信息,我想知道如何正确使用它。

1)什么时候应该在非成员函数前写关键字static

2) 在标头中定义静态非成员函数是否危险?为什么(不)?


(附带问题)

3) 是否可以以某种方式在头文件中定义一个类,以便它只在您首先使用它的翻译单元中可用?

(我问这个的原因是因为我正在学习 STL,它可能是我的谓词等(可能是函子)的一个很好的解决方案,因为我不喜欢定义成员以外的函数-cpp 文件中的函数)

(另外,我认为它在某种程度上与原始问题相关,因为根据我目前的推理,它会在函数之前做与 static 相同的事情)

编辑

看到一些答案时提出的另一个问题:

4) 很多人告诉我,我必须在头文件中声明静态函数,并在源文件中定义它。但是静态功能是翻译单元独有的。链接器如何知道哪个它是唯一的翻译单元,因为头文件不直接与源文件相关(仅当您包含它们时)?

【问题讨论】:

    标签: c++ static linker


    【解决方案1】:

    static,我认为您正在使用它,是一种符号隐藏的方法。声明为 static 的函数没有全局可见性(类 Unix 的 nm 会将这些显示为 't' 而不是 'T')。不能从其他翻译单元调用这些函数。

    对于 C++,static 在这个意义上已或多或少地被匿名命名空间所取代,例如,

    static int x = 0;
    

    相当于

    namespace {
      int x = 0;
    }
    

    请注意,匿名命名空间对于每个编译单元都是唯一的。

    static 不同,匿名命名空间也适用于类。你可以这样说

    namespace {
     class Foo{};
    }
    

    并为其他翻译单元中不相关的类重用该类名。我认为这符合您的第 3 点。

    编译器实际上给您以这种方式定义的每个符号一个唯一的名称(我认为它包括编译时间)。这些符号对另一个翻译单元永远不可用,并且永远不会与来自另一个翻译单元的符号发生冲突。

    请注意,所有声明为inline 的非成员函数也默认为static。这是static 最常见的(也是隐含的)用法。至于第 2 点,在标头中定义 static 而不是 inline 函数是一个非常极端的情况:它本身并不危险,但它很少有用,可能会令人困惑。这样的函数可能会或可能不会在每个翻译单元中发出。如果您从未在某些 TU 中实际调用该函数,编译器可能会生成警告。如果该静态函数中有一个静态变量,那么即使在单个 .h 中有一个定义,您也会为每个翻译单元获得一个单独的变量,这可能会造成混淆。只是没有很多(非内联)用例。

    关于第 4 点,我怀疑那些人将static 的静态成员函数含义与static 的链接含义混为一谈。这是为后者使用匿名命名空间的一个很好的理由。

    【讨论】:

    • 我想你会在标题中写这些代码示例?如果是这样,您能否解释一下链接器如何知道将其绑定到哪个翻译单元? (最好在你的回答中)
    • 我从未在标题中使用过匿名命名空间。我将它用于仅在一个翻译单元范围内使用的辅助函数/类。恐怕我没有完全按照您的意思说,因此它只能在您首先使用它的翻译单元中使用。你知道翻译单位是整个后 CPP 的混乱,对吧?单个源文件不是翻译单元。
    • 但是如果你在源文件中定义了一些东西,它已经是翻译单元独有的了,对吧?那么为什么在标题中使用它呢?恐怕我也不完全遵循你的最后一个问题。翻译单元是否不是 cpp 文件 + 您包含在其中的标头,由编译器转换为 .obj 文件
    • 最后一行是对的。翻译单元 (TU) 是(通常)产生 .o/.obj 的任何东西。我认为混淆是你的第一行:即使你没有在标题中提到它,如果函数/类声明没有 static 或不在匿名命名空间中,它是全局的并且可能会与另一个 TU 中的定义。
    • 至于 4):简短回答:不要这样做。 “翻译单元”是编译器在创建 .o(bj): 标头 + 实现时看到的。在您的情况下(静态 myvar,静态 my_function),我不会将它们放在 .h 中 - 仅放在 .cpp 中。恕我直言...
    【解决方案2】:

    关键字“static”被重载表示几个不同的东西:

    • 它可以控制可见性(C 和 C++)

    • 它可以在子程序调用(C和C++)之间持久化一个变量

      ...和...

    • 它可以使方法或成员应用于整个类(而不仅仅是一个类实例:仅限 C++)

    简短回答:最好不要使用任何语言工具,除非

    a) 你很确定你需要它

    b) 你很确定你知道你在做什么(即你知道你为什么需要它)

    在 .cpp 文件中声明静态变量或独立函数绝对没有错。在标头中声明静态变量或独立函数可能是不明智的。而且,如果您确实需要为类函数或类成员“静态”,那么头文件可以说是定义它的最佳位置。

    这是一个很好的链接:

    http://www.cprogramming.com/tutorial/statickeyword.html

    '希望有帮助

    【讨论】:

    • @Alessandro Pezzato - 我没有标记任何人。但我感谢您的支持,如果这是您的意图:) 谢谢。
    • 很好的答案,但(imo)不完整/细节太少。不过我没有投反对票。
    【解决方案3】:

    当非成员函数仅在声明它们的代码文件中可见时,您应该将它们定义为静态函数。

    cplusplus.com 也提出了同样的问题

    【讨论】:

    • @kol - 严格来说是“翻译单元”,通常与目标文件相同。因此,如果您在多个“c”文件中包含标题,它将最终出现在每个文件中
    • 使用“翻译单元”而不是“代码文件”可能会得到更好的答案,尽管 CPP 文件的行为基本上如所述。
    • 但是我应该在 header 还是 cpp 中定义静态函数?因为如果我在 cpp 中声明和定义一个非静态函数,它也绑定到那个翻译单元,对吧?如果我在标题中定义它,那么链接器如何知道它是唯一的翻译单元?如果我在标头中声明它,并在 cpp 中定义它,那么(后者)链接器怎么知道?
    • 理想情况下,您应该在头文件中声明它,并在代码文件(cpp 文件)中定义它。
    猜你喜欢
    • 2010-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多