虚拟成员函数的定义是否强制在同一转换单元中动态初始化静态数据成员?
Does the definition of a virtual member function force dynamic initialization of a static data member in the same translation unit?
考虑以下两个翻译单元:
// foo.cpp
#include <iostream>
class Foo {
public:
virtual ~Foo() = default;
virtual void bar();
private:
static int _baz;
};
static int f() {
std::cout << "f calledn";
return 42;
}
int Foo::_baz = f();
void Foo::bar() {
std::cout << "Baz::bar calledn";
}
和
// main.cpp
#include <iostream>
int main() {
std::cout << "main calledn";
}
当将两个翻译单元编译为单个可执行文件时(例如,使用g++ -std=c++17 main.cpp foo.cpp
时,选择优化级别或两个 cpp 文件的顺序无关紧要(,生成的可执行文件会打印
f 称为
主调用
无论使用三个主要编译器中的哪一个GCC,Clang和MSVC来编译它。您可以在魔杖盒上亲自查看行为。
我的问题是:即使程序中根本没有使用整个类Foo
,标准是否保证Foo::_baz
将被初始化(从而调用f
?
我相信是这样;我的理由如下:
根据 [basic.start.dynamic]/4,在执行 main 的第一个语句之前不必初始化Foo::_baz
,但是
如果 [初始化] 被推迟,则它强烈发生在任何非初始化 ODR 使用任何非内联函数或非内联变量之前,该函数或非内联变量在与要初始化的变量相同的翻译单元中定义。
在这里,"非初始化 odr-use"定义为
[...]不是由非本地静态或线程存储持续时间变量的初始化直接或间接引起的ODR使用([basic.def.odr](
在 [basic.start.dynamic]/3 中。但根据 [basic.def.odr]/7,
如果虚拟成员函数不是纯函数,则使用 ODR。
由此我得出结论,Foo::bar
的定义是非初始化 odr 使用在与Foo::_baz
相同的翻译单元中定义的非内联函数,因此Foo::_baz
将被初始化。
我觉得这种推理的奇怪之处在于,Foo::_baz
的延迟初始化需要在 ODR 使用Foo::bar
之前发生,即在定义Foo::bar
之前(wtf?!(,因为定义本身就是 odr 使用。这让我觉得我的推理可能有缺陷。
再说一遍:标准是否保证Foo::_baz
将被初始化(从而调用f
,即使其翻译单元中的任何内容都没有在程序中使用?如果是,我们是否可以说这何时会发生(考虑到在定义虚拟成员函数之前必须发生的奇怪的排序约束(,如果不是,我的推理错误在哪里?
静态初始化不受虚函数的影响,与动态初始化的关系是关于排序的,对于常量初始值设定项,它如[class.static.data]/2
中所述
[注意:一旦定义了静态数据成员,即使没有创建其类的对象,它仍然存在。
然而[basic.start.dynamic]/4
静态存储持续时间的非局部非内联变量的动态初始化是在 main 的第一条语句之前排序还是延迟,这是实现定义的。如果它被推迟,则在与要初始化的变量相同的翻译单元中定义的任何非内联函数或非内联变量的任何非初始化odr使用之前,它就会发生。
即使实现选择推迟初始化,标准要求它发生。 并作为前一条的脚注:
在这种情况下,初始化具有静态存储持续时间且具有副作用的非局部变量,即使它本身不是 odr 使用的。
- 什么时候调用组成单元对象的析构函数
- 防止主数据类型C++的隐式转换
- 模板参数替换失败,并且未完成隐式转换
- 努力将整数转换为链表。不知道我在这里做错了什么
- HEX值到wchar_t字符(UTF-8)的转换
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将 Qvector<uint8_t> 转换为 QString
- 如何在cuSparse中使用cusparseXcoo2csr从coo转换为csc
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 在c++中使用nlohmann从类到json的转换
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 虚拟成员函数的定义是否强制在同一转换单元中动态初始化静态数据成员?
- 将 lambda 函数转换为另一个编译单元中的普通函数会缩短编译时间吗?
- Matlab 编码器转换可变大小单元格错误
- 如何在 Eclipse 中将我的项目从多个编译单元转换为单个编译单元
- 错误:无法<int>在分配中将"单元格*"转换为"列表<int>*"
- 包含在许多转换单元中时静态常量的开销
- 将MATLAB单元类型转换为c++
- 简单的C++单元转换
- 可以将带有类的c++头文件转换为Delphi单元吗?