【问题标题】:Why do you _have_ to initialize a C++ static member variable?为什么你_必须_初始化一个 C++ 静态成员变量?
【发布时间】:2010-11-04 15:09:23
【问题描述】:

我知道您通常会在 .cpp 文件中初始化静态成员变量。但我的问题是:你为什么

这是一个例子:

#include <vector>

using namespace std;

class A {
    public:
        static vector<int> x;
};

main() {
    int sz = A::x.size();
}

这会导致编译器错误:undefined reference to 'A::x'

但是,这:

#include <vector>

using namespace std;

class A {
    public:
        static vector<int> x;
};

// Initialize static member
vector<int> A::x;

main() {
    int sz = A::x.size();
}

编译并运行良好。

我可以理解我是否使用默认构造函数以外的东西来初始化向量,但我不是。我只想创建一个大小为 0 的向量。当然,任何静态成员都必须在程序初始化时分配内存,那么为什么编译器不直接使用默认构造函数呢?

【问题讨论】:

    标签: c++ static static-members


    【解决方案1】:

    不是关于初始化,而是关于定义。 或者更准确地说:这是关于知道哪个编译单元 (.cpp) 将保存对象(必须在某些地方唯一定义)

    所以,所需要的只是将定义放在某个地方,在一个独特的地方,即cpp,让编译器知道当类的静态对象被调用,它在那里定义,没有其他地方。 (如果您尝试在标头中定义静态,包括此标头的每个 cpp 都会有一个定义,因此无法知道应该在哪里定义它 - 如果您需要使用它,请手动初始化) .

    【讨论】:

    • +1 但您应该删除其中一个副本。对于对象,RAII 使初始化(即使只是默认构造函数)成为定义的结果。这是否适用于原始指针、int 等内置类型?
    • 我的意思是如果你愿意,你可以在那里添加初始化。我会添加精度。
    • @Steve POD 类型构造函数仅在语法上,所以是的,它确实有效,但它实际上并没有做任何事情(或者更准确地说,它允许什么都不做 - 根据 C++ 标准)。
    • 谢谢,这很有意义。我想我想头文件中的 declaration 足以保留内存。但当然不可能,因为头文件包含在许多目标文件中。有意义的是,您必须通过在一个 .cpp 文件中提供静态 定义 来明确说明哪个目标文件将分配内存。
    • 来自其他语言时可能仍然很奇怪,因为原因与旧的文件编译单元系统有关。不确定它是否会在未来十年内保留。似乎对 C++15-16 或更高版本的基于模块的系统很感兴趣。
    【解决方案2】:

    您从单个编译单元的角度来看它。

    但语言必须假设可能存在多个编译单元。那么现在静态对象是在哪个编译单元中创建的呢?基本上不允许编译器做出决定,工程师必须做出决定。

    【讨论】:

      【解决方案3】:

      undefined reference to 'A::x' 不是编译器错误;这是一个链接器错误。这意味着A::x 的定义无法在链接在一起以形成您的程序的任何翻译单元中找到。静态成员变量具有外部链接,并且必须在一个翻译单元中定义。除非您编写任何具有外部链接的定义,否则编译器不会生成定义。

      【讨论】:

        【解决方案4】:

        你所说的初始化就是定义。您需要在某处定义静态成员。类中的部分只是一个声明。

        这主要是因为在标题中包含定义会导致巨大的问题(因为您不能将该标题包含在一个以上的翻译单元中而不会导致多个定义)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-04
          • 2020-05-31
          • 2023-04-02
          • 1970-01-01
          相关资源
          最近更新 更多