class 静态变量初始化的规则是什么?
What are rules for a class static variable initialization?
我有一些遗留代码,我需要为消息添加一个新的 class(这与我的问题无关)。但事实证明,我需要声明一个空的构造函数才能初始化一些静态。不是默认构造函数或编译器提供的,而是用户定义的空。我试图将代码缩减为 MWE,这里是我得到的:
#include <iostream>
using namespace std;
struct Test
{
Test() {cout << "Test::Test()" << "\n";}
void dummy(){}
};
template<typename T>
struct Message
{
Message()
{
test.dummy(); // this call have to be here in order to initialize Test, but why?
}
static Test test;
};
template<typename T>
Test Message<T>::test;
struct A : public Message<A>
{
//A(){} // uncomment this (and comment the default one) to call the Test constructor
A() = default;
};
int main()
{
}
事情是这样的:
- 程序本身是空的,即没有创建任何实例。
- 有一个
A
class 的 CRTP,这似乎对示例很重要。
A
的基类有一个静态声明,我期待它的构造函数被调用。
- 有一个对函数的虚拟调用,它什么都不做,但也很关键。
问题是,如果我不提供自定义构造函数,则永远不会调用静态构造函数。我不明白为什么我需要这个?默认值或编译器生成有什么区别?为什么我需要调用虚拟函数?
我相信这是有规定的。我用不同版本的 gcc 和 clang 检查了它——行为是一样的。我非常感谢指向 standard/documentation.
的链接
如果您将 A
构造函数保留为默认值并且从不调用它,则无需生成它,因此也无需创建 test
。如果您在定义时明确默认它,调用 A
构造函数或访问 A::test
它将被正确初始化。
12.1 Constructors [class.ctor]
7
A default constructor that is defaulted and not defined as deleted is implicitly defined when it is odr-used (3.2) to create an object of its class type (1.8) or when it is explicitly defaulted after its first declaration.
struct A : public Message<A>
{
A() = default; // no constructor is emitted unless A is instantiated
A(); // declaration
};
A::A() = default; // explicit default definition
int
main()
{
A a; // instantiation
A::test; // just explicitly access test so it is initialized regardless of A constructor
}
C++14 [temp.inst]/2:
Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.
这清楚地表明 Message<A>::test
不会被初始化,除非它以需要其定义存在的方式使用。
程序中唯一需要定义的表达式是 Message<A>
的构造函数中的 test.dummy()
;因此,如果删除该表达式,则不得初始化 test
。
对于存在 test.dummy()
的情况,请注意它位于模板函数内部,即 Message<A>
的构造函数。如果从未实例化此构造函数,则不会考虑 test.dummy()
。
正如 VTT 所指出的,[class.ctor] 表示 A
的显式默认构造函数意味着没有定义构造函数,除非使用了 A
。
您的代码不使用 A
,因此未定义 A
的构造函数,因此没有调用基础 class 构造函数(这只会如果定义了 A
的构造函数,则会发生),因此构造函数模板 Message<A>()
未实例化,因此 test
不需要存在。
我有一些遗留代码,我需要为消息添加一个新的 class(这与我的问题无关)。但事实证明,我需要声明一个空的构造函数才能初始化一些静态。不是默认构造函数或编译器提供的,而是用户定义的空。我试图将代码缩减为 MWE,这里是我得到的:
#include <iostream>
using namespace std;
struct Test
{
Test() {cout << "Test::Test()" << "\n";}
void dummy(){}
};
template<typename T>
struct Message
{
Message()
{
test.dummy(); // this call have to be here in order to initialize Test, but why?
}
static Test test;
};
template<typename T>
Test Message<T>::test;
struct A : public Message<A>
{
//A(){} // uncomment this (and comment the default one) to call the Test constructor
A() = default;
};
int main()
{
}
事情是这样的:
- 程序本身是空的,即没有创建任何实例。
- 有一个
A
class 的 CRTP,这似乎对示例很重要。 A
的基类有一个静态声明,我期待它的构造函数被调用。- 有一个对函数的虚拟调用,它什么都不做,但也很关键。
问题是,如果我不提供自定义构造函数,则永远不会调用静态构造函数。我不明白为什么我需要这个?默认值或编译器生成有什么区别?为什么我需要调用虚拟函数?
我相信这是有规定的。我用不同版本的 gcc 和 clang 检查了它——行为是一样的。我非常感谢指向 standard/documentation.
的链接如果您将 A
构造函数保留为默认值并且从不调用它,则无需生成它,因此也无需创建 test
。如果您在定义时明确默认它,调用 A
构造函数或访问 A::test
它将被正确初始化。
12.1 Constructors [class.ctor]
7 A default constructor that is defaulted and not defined as deleted is implicitly defined when it is odr-used (3.2) to create an object of its class type (1.8) or when it is explicitly defaulted after its first declaration.
struct A : public Message<A>
{
A() = default; // no constructor is emitted unless A is instantiated
A(); // declaration
};
A::A() = default; // explicit default definition
int
main()
{
A a; // instantiation
A::test; // just explicitly access test so it is initialized regardless of A constructor
}
C++14 [temp.inst]/2:
Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.
这清楚地表明 Message<A>::test
不会被初始化,除非它以需要其定义存在的方式使用。
程序中唯一需要定义的表达式是 Message<A>
的构造函数中的 test.dummy()
;因此,如果删除该表达式,则不得初始化 test
。
对于存在 test.dummy()
的情况,请注意它位于模板函数内部,即 Message<A>
的构造函数。如果从未实例化此构造函数,则不会考虑 test.dummy()
。
正如 VTT 所指出的,[class.ctor] 表示 A
的显式默认构造函数意味着没有定义构造函数,除非使用了 A
。
您的代码不使用 A
,因此未定义 A
的构造函数,因此没有调用基础 class 构造函数(这只会如果定义了 A
的构造函数,则会发生),因此构造函数模板 Message<A>()
未实例化,因此 test
不需要存在。