【问题标题】:Scope of the static class data member静态类数据成员的范围
【发布时间】:2013-02-16 07:10:35
【问题描述】:

如果我有课:

Object.h

class Object
{
public:
    static int number;
};

Object.cpp

int Object::number = 5;

Object::number 的范围是否保证比任何已创建的Object 实例的范围更持久?即使它是在另一个源文件中全局声明的?

【问题讨论】:

  • 类静态和非静态实例的链接是有意的和不同的。即使Object没有 个实例存在,Object::number 也会存在,更不用说任何Object 的特定实例的寿命。只有一个(除非它是一个模板,但从技术上讲,这不是同一个 class,因为它是一个生成的推论)。
  • 顺便说一句,您要问的是“终身”,而不是“范围”。范围是源文件中名称可见的部分。生命周期是对象存在的运行时间。
  • @WhozCraig:另一方面,我相信在初始化Object::number 之前,可以构造和使用Object 的实例...
  • @MooingDuck - 我认为这回答了 OP 的确切问题。
  • @MooingDuck 在我确认或否认这是可能的之前,我必须认真地将自己包装到标准中的对象生命周期和全局初始化及其格式定义中,但这丝毫不会让我感到惊讶如果它是。全局初始化对我来说总是很容易出错,所以我尽量避免它。

标签: c++ class static global-variables


【解决方案1】:

是的,它具有“静态存储持续时间”,这意味着它“一直”存在 [如果它有一个非标准构造函数,则在“main”开始之前调用构造函数——这对于大多数意图来说应该足够了及用途]

【讨论】:

  • 它可能存在但可能未初始化为您期望的值。
【解决方案2】:

标准保证具有静态存储时长的对象在程序的整个运行期间都存在。

C++03,3.7.1 静态存储时长§1

所有既不具有动态存储持续时间也不是本地对象的对象具有静态存储持续时间。这些对象的存储将持续到程序的持续时间

在你的例子中 §4 也是相关的:

应用于类定义中的类数据成员的关键字static 赋予数据成员静态存储持续时间。

【讨论】:

  • 它可能存在但可能未初始化为您期望的值。
【解决方案3】:

有点,但只是因为int 是一个特例。例如,假设你写Object.cpp

Object o = {};
int Object::number = 5;

然后对象o 具有静态存储持续时间,就像Object::number 一样。它名义上是在number之前创建的,之后会被销毁,但是由于它们都是POD,所以这个销毁实际上没有效果。

如果numbero 有非平凡的析构函数,那么number 将在o 之前被销毁。 numbero 类的静态成员这一事实并没有对它进行任何特殊处理,就破坏顺序而言。

如果o 在另一个源文件中处于关闭状态,则构造顺序未指定,而破坏顺序是构造的相反顺序(同样,如果它们有非平凡的析构函数——int 是一种特殊情况因为它没有)。

【讨论】:

    【解决方案4】:

    考虑一下这个 g++ 程序:

    #include <iostream>
    #define X() (std::cout << __PRETTY_FUNCTION__ << "\n")
    
    struct M {
     M() { X(); }
     ~M() { X(); }
    };  
    
    struct C {
     C() { X(); }
     ~C() { X(); }
     static M m;
    };
    C c;
    M C::m;
    int main () { X(); }
    

    在这个程序中,c 必须在C::m 之前初始化,并且必须在C::m 之后销毁。如果你编译这个程序并考虑它的输出,你会看到类似:

    C::C()
    M::M()
    int main()
    M::~M()
    C::~C()
    

    所以,不,一般来说,“[成员] 的 [生命周期]”“保证比所创建的任何 Object 实例的 [生命周期] 长?” p>

    【讨论】:

    • 我也这么认为,但 Mike Seymour 观察到具有 constexpr 构造函数和原语的对象有一种特殊情况:§ 3.6.2/2
    • 对,所以特别是 OP 确实保证了问题中描述的 Object。但一般来说,他对所有其他种类的对象都没有这样的保证。
    【解决方案5】:

    是的,有两个原因:

    • 它具有静态存储持续时间,因此它的存储持续到程序的生命周期
    • 它有一个没有构造函数的类型,用常量表达式初始化。

    这意味着它在静态初始化阶段被初始化,在任何用户定义的代码(包括静态对象的构造函数)运行之前。因此,它保证在任何代码可以访问它之前存在并被初始化。

    如果它有构造函数或非常量初始化器,那么它将在动态初始化期间连同所有其他此类对象一起被初始化。在这种情况下,另一个静态对象的构造函数或初始化程序可能会在初始化之前访问该对象。该问题有时被称为“静态初始化顺序惨败”。

    【讨论】:

      猜你喜欢
      • 2012-06-25
      • 1970-01-01
      • 1970-01-01
      • 2015-09-11
      • 2016-01-09
      • 1970-01-01
      • 1970-01-01
      • 2016-10-15
      • 1970-01-01
      相关资源
      最近更新 更多