Clang / LLVM 7和8每TU一次初始化一个内联静态数据成员。据我了解C ++ 17,这是不正确的。
尽管可以在多个TU中定义一个内联变量,但编译器和/或链接器必须确保该变量在程序中仅存在一次,因此仅被初始化一次。
以下小程序显示了Clang / LLVM的情况(已在具有LLVM编译器工具链扩展的Visual Studio 2017和2019 RC中测试):
// header.h
#include <iostream>
struct A
{
A() { std::cout << "ctor " << this << std::endl; }
~A() { std::cout << "dtor " << this << std::endl; }
void f() { std::cout << "f " << this << std::endl; }
};
struct S
{
inline static A a; // C++17 inline variable, thus also a definition
};
// TU1.cpp
#include "header.h"
int main()
{
S::a.f();
}
// TU2.cpp
#include "header.h"
// TU3.cpp
#include "header.h"
// TU4.cpp
#include "header.h"
该程序打印:
ctor 010D4020
ctor 010D4020
ctor 010D4020
ctor 010D4020
f 010D4020
dtor 010D4020
dtor 010D4020
dtor 010D4020
dtor 010D4020
这是A的唯一对象(实际上是每个TU一个)的四个初始化,而不是(C ++ 17要求的)完全一个。 >
程序应打印:
ctor 010D4020
f 010D4020
dtor 010D4020
顺便说一下,这就是MSVC的作用。
这是clang / LLVM中的错误,对吧?
答案 0 :(得分:7)
inline
关键字的主要特征是它以两种方式修改了ODR规则:
结果对象被“折叠”成single instance:
具有外部链接的内联函数或变量在所有翻译单元中应具有相同的地址。
C ++ 17中唯一的补充是它还将allows和static
数据成员声明也定义为。就是这样。
static
数据成员仍然具有相同的 linkage (在您的情况下为external),storage duration和lifetime,并且对于所有实际情况用途就像全局定义的变量一样。
参见[class.static.data]/6:
静态数据成员的初始化和销毁完全类似于非局部变量
从本质上讲,它应该与此相同:
struct A
{
A() { std::cout << "ctor "; }
~A() { std::cout << "dtor "; }
};
A a; // in one of the TU's
extern A a; // in all other TU's
结论:
这是Clang中的错误。 static
S::a
必须初始化并销毁一次。
答案 1 :(得分:1)
This bug is fixed在基于SVN r361807的当前快照中。