Windows上的Clang/LLVM 7.0.1多次初始化内联静态数据成员

x y*_*x y 13 c++ clang llvm-clang c++17

Windows上的Clang/LLVM 7.0.1 每个TU初始化一次内联静态数据成员.据我所知,C++ 17这是不正确的.

尽管可以在多个TU中定义内联变量,但编译器和/或链接器必须确保它在程序中仅存在一次,因此仅初始化一次.就像多重定义的内联函数一样,在程序中只存在一次.请参阅以下小程序:

// 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 
};
Run Code Online (Sandbox Code Playgroud)

// TU1.cpp

#include "header.h"

int main()
{
  S::a.f();
}
Run Code Online (Sandbox Code Playgroud)

// TU2.cpp

#include "header.h"
Run Code Online (Sandbox Code Playgroud)

// TU3.cpp

#include "header.h"
Run Code Online (Sandbox Code Playgroud)

// TU4.cpp

#include "header.h"
Run Code Online (Sandbox Code Playgroud)

该程序打印:

ctor 010D4020
ctor 010D4020
ctor 010D4020
ctor 010D4020
f 010D4020
dtor 010D4020
dtor 010D4020
dtor 010D4020
dtor 010D4020
Run Code Online (Sandbox Code Playgroud)

这是A的唯一对象的四个初始化(实际上每个TU一个)而不是一个(如C++ 17要求).

该程序应打印:

ctor 010D4020
f 010D4020
dtor 010D4020
Run Code Online (Sandbox Code Playgroud)

顺便说一句,这就是MSVC所做的.

这是clang/LLVM中的一个错误,对吧?

rus*_*tyx 7

inline关键字的主要特征是它以两种方式修改了ODR规则:

  1. 允许多个定义(有一些限制)
  2. 结果对象被“折叠”成一个实例

    具有外部链接的内联函数或变量在所有翻译单元中应具有相同的地址。

在C ++ 17的唯一的另外的是,它也允许一个static数据成员声明是一个定义。而已。

一个static数据成员仍然具有相同的链接外部你的情况),贮存期使用寿命,并为所有实用目的的作品就像一个全局定义的变量。参见[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
Run Code Online (Sandbox Code Playgroud)

结论:

这是Clang中的错误。在static S::a必须进行初始化和销毁一次。