【问题标题】:C++ static variables in static class methods defined in headers头文件中定义的静态类方法中的 C++ 静态变量
【发布时间】:2016-06-08 11:42:29
【问题描述】:
// SomeOtherClass.hpp
#pragma once

int someOtherCallMe();

class SomeOtherClass {
  public:

    static int callMe() {
      static int _instance = 7;
      ++_instance;
      return _instance;
    }
};


// SomeOtherClass.cpp
#include "SomeOtherClass.hpp"

int
someOtherCallMe() {
  return SomeOtherClass::callMe();
}

// main.cpp

#include "SomeOtherClass.hpp"

#include <iostream>

int
main() {

  std::cout << SomeOtherClass::callMe();
  std::cout << someOtherCallMe();

  return 0;
}

我有三个文件:SomeOtherClass.hpp/cpp、main.cpp。这些文件生成两个二进制文件:共享库(SomeOtherClass.cpp)和可执行文件(main.cpp,与共享库链接)。

C++ 是否保证static &lt;any-type&gt; _instance 在程序执行期间是单个变量(不管它定义了多少个二进制文件)?

注意 澄清情况。我在这种情况下看到的困惑是,一方面,SomeOtherClass::callMe 在程序中定义了两次,这是意料之中的(因为类静态成员函数实际上是具有内部链接的常规函数​​,如果它们被定义到位,比如在这种情况下),这就是你可以从反汇编中看到的。因为我们在机器代码中有两个带有静态局部变量的函数。语言/标准如何限定他们的行为?

【问题讨论】:

  • 使用 MS Visual Studio 时,您需要使用正确的 __declspec 来构建 DLL 并使用 DLL 使其工作。
  • 是的,我知道谢谢。
  • 如果问题真的是关于跨 DLL 边界的静态变量,那么应该在标题中提到,并且在正文中更突出

标签: c++ class static


【解决方案1】:

是的。静态将是单个值。很多其他的东西没有很好的定义或者对标准来说是新的。 (如果它们是全局的,它们什么时候初始化?函数中的静态初始化代码是线程安全的吗?)但是,是的,你可以指望只有一个。

这里唯一的说明是在标准之外,但如果您正在创建共享库(.so 或 .dll),则具有实际重要性:您不能将 C++ 类库静态(私有)链接到共享库。否则,如果您在两个不同的共享库中执行此操作,则会生成两个副本。 (此注释适用于有关库的所有内容,而不仅仅是静态变量。如果您这样做,那么所有内容都会重复。)

编辑:在许多平台(如 Linux 和 Windows)上,这可用于有目的地“隐藏”您的静态变量。如果您不使您的函数/类在 dll/so 之外可访问(使用 declspec 或可见性属性),那么您可以确保您的 dll/so 拥有整个类的自己的副本。这种技术可以帮助减少库之间不必要的交互。但是,就您而言,听起来您真的只想要一个,如果您的类在所有库中都具有适当的可见性(仅在一个中可见,并且其他库链接到该库),就会出现这种情况。

再次编辑以参考标准

如果具有外部链接的函数在一个翻译单元中声明为内联,则应在其出现的所有翻译单元中声明为内联;不需要诊断。具有外部链接的内联函数在所有翻译单元中应具有相同的地址。 extern 内联函数中的静态局部变量始终引用同一个对象

7.1.2.4,C++14

【讨论】:

  • 亲爱的 Rob,谢谢你的努力,你的回答似乎是我现在想要的最接近的,我真的不知道你为什么被否决,mb 你一开始写的东西很奇怪,我实际上并没有查看更改历史记录,或者 mb 它只是草率的 stackoverflow 阅读器。如果您能提供一些对标准和/或一些有价值的资源的参考,我将不胜感激,那是什么类型的联系,以及标准/语言如何限定这种结构..
  • 我想我被否决了,因为这是一个复杂的话题,很难用是/否来回答。在我被否决后,我还添加了澄清。我认为标准中没有任何内容可以涵盖 dll 和共享二进制文件。该信息来自项目负责人(我),他必须管理具有数十个 dll 和大量开发人员的产品。我们已经从所有这些错误中吸取了教训。底线:如果它是共享的,在某个地方定义一次,然后正确导出,然后编译器会处理其余的事情。
  • 是的,我还看到它是一个所有内容都内联的仅标头库,或者它是一个共享库,其中所有内容都在翻译单元中定义。我知道这更清楚(哦,c ++ ...)))。但我只是好奇是否有定义这种情况的东西,甚至不是 dll/executable 的情况,但即使有像 SomeOtherClass.hpp 这样的标头在多个翻译单元中使用的情况,是否保证变量会只有一个。也请参阅更新。
  • 如果没有 dll,只有“常规”库和目标文件,那么可以。绝对保证只有一个。
  • 但是混乱还是一样,为什么?因为实际上会有与翻译单元一样多的SomeOtherClass::callMe 函数。那么它如何解析静态变量,它如何限定它。因为在常规命名空间声明的静态变量的情况下,变量的数量将与翻译单元一样多。那么什么是静态局部变量呢?
【解决方案2】:

C++ 是否保证在程序执行期间静态 _instance 将是单个变量(无论它定义了多少个二进制文件)?

我认为语言对此没有什么可说的。它没有谈论静态库或动态库。

实现的责任是提供机制以确保可以有一个定义。用户需要确保他们使用实现提供的机制在函数中定义 static 变量。

【讨论】:

  • 我同意您的观点,即用户选择自己想要的东西并用语言的方式去做。但在这种情况下,我会说因为静态函数 (SomeOtherClass::callMe) 在代码中是重复的。静态变量也应该被复制,但至少在 g++ 中不是这样。但另一方面,它不应该重复,因为正如语言所说,static 保证单个对象。
猜你喜欢
  • 2011-05-30
  • 2014-04-01
  • 2012-06-24
  • 2015-02-18
  • 2011-06-29
  • 2013-08-04
  • 2011-01-17
  • 1970-01-01
  • 2018-12-10
相关资源
最近更新 更多