【问题标题】:What is the difference between static objects defined in a header file and static objects defined in a cpp file?头文件中定义的静态对象和 cpp 文件中定义的静态对象有什么区别?
【发布时间】:2019-11-05 00:24:33
【问题描述】:

假设我有一个头文件,并假设复制宏已得到处理: f1.h:

Object& getObject() {
    static Object obj;
    return obj;
}

在包含此标头的任何地方,翻译单元都将拥有自己的 obj 副本。那么,如果a.cpp、b.cpp、c.h包含这个header,obj会被实例化3次?

现在,如果我有以下内容:

f2.h:

 Object& getObject();

f2.cpp:

  #include <f2.h>
  Object& getObject() {
      static Object obj;
      return obj;
  }

在这种情况下,我的标头被包含在内,但符号仅在 cpp 文件中创建。因此,链接器只找到在 cpp 文件中创建的单个静态 obj 对象,而每个引用 .h 文件的翻译单元都获得该符号?

这是对正在发生的事情的正确直觉,还是这里有更多的作用?

【问题讨论】:

  • “在任何包含这个头的地方,翻译单元都会有自己的obj副本。” 这个假设是错误的。该对象将被创建一次且仅一次。在头部的函数定义前加上inline,以避免函数的多个定义。
  • 您知道如果在标题右侧定义方法时不使用 inline 关键字,尝试此操作会遇到问题吗?
  • 如果函数在头文件中定义,并且不是内联的,它将在包含该头文件的每个编译单元(又名源文件)中定义。所以程序不会链接 - 函数是否有静态变量。如果函数是内联的,则实现(可能是编译器,也可能是链接器)将解决问题 - 再次,无论函数是否具有静态。

标签: c++ static linker translation-unit


【解决方案1】:

因此,如果 a.cpp、b.cpp 和 c.h 包含此标头,则 obj 将是 实例化 3 次?

应用不会链接。最终你会得到一个重复的函数链接器错误。

在第二种情况下,您只有一个对象。

无论如何,正确的做法是将所有定义都放在 .cpp 文件中,或者在头文件中将函数定义为 inline,这样无论包含多少次,它们都只定义一次。

【讨论】:

  • 不利的一面是,这使链接器的事情变得更加复杂,而链接已经是该过程中最困难的一步。如果可能,最好在 cpp 中定义静态变量。
  • 他所问的与静态变量无关。即使没有静态,应用也不会链接。
  • 如果我确实在标题中添加了内联(我并不是说这是最好的方法,只是为了便于理解),是否仍然只创建一个静态对象每个翻译单元的功能,还是一个功能?
  • 整个项目只有一个函数,因此只有一个静态变量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-08
  • 1970-01-01
相关资源
最近更新 更多