72

constinit是P1143中提出的 C++20 中的新关键字说明符。

标准中提供了以下示例:

const char * g() { return "dynamic initialization"; }
constexpr const char * f(bool p) { return p ? "constant initializer" : g(); }
constinit const char * c = f(true);     // OK
constinit const char * d = f(false);    // ill-formed

想到几个问题:

  • 是什么constinit意思?为什么介绍它?我们应该在哪些情况下使用它?

  • 它是否使变量不可变?是暗示const还是constexpr

  • 变量可以同时是constconstinit吗?constexpr和怎么样constinit

  • 说明符可以应用于哪些变量?为什么我们不能将它应用于非static、非thread_local变量?

  • 它有什么性能优势吗?

该问题旨在用作constinit一般即将提出的问题的参考。

4

2 回答 2

72
  • 是什么constinit意思?为什么介绍它?我们应该在哪些情况下使用它?

使用静态存储持续时间初始化变量可能会导致两种结果¹:

  1. 变量在编译时初始化(常量初始化);

  2. 变量在控件第一次通过其声明时被初始化。

情况 (2) 是有问题的,因为它可能导致静态初始化顺序失败,这是与全局对象相关的危险错误的来源。

constinit关键字只能应用于具有静态存储持续时间的变量。如果修饰变量在编译时没有被初始化,那么程序是错误的(即不能编译)。

使用constinit确保变量在编译时被初始化,并且静态初始化顺序失败不会发生。


  • 它是否使变量不可变?是暗示const还是constexpr

没有也没有。

不过,constexpr确实暗示constinit


  • 变量可以同时是constconstinit吗?constexpr和怎么样constinit

它可以是 constconstinit。它不能同时是constexprconstinit。从措辞:

decl-specifier-seq 中最多出现constexpr,consteval和关键字之一。constinit

constexpr不等同于const constinit,因为前者要求不断破坏,而后者则不然。


  • 说明符可以应用于哪些变量?为什么我们不能将它应用于非static、非thread_local变量?

它只能应用于具有静态或线程存储持续时间的变量。将它应用于其他变量是没有意义的,就像constinit静态初始化一样。


  • 它有什么性能优势吗?

不会。但是,在编译时初始化变量的附带好处是它在程序执行期间不需要指令来初始化。constinit帮助开发人员确保情况确实如此,而无需猜测或检查生成的程序集。


¹:见https://en.cppreference.com/w/cpp/language/storage_duration#Static_local_variables

于 2019-09-08T19:43:59.090 回答
3

主要问题

仅当控件通过其声明或定义时,才认为对象已初始化;否则(即控件跳转到声明或定义此对象的源文件中定义的函数,它根本看不到它)对该未初始化对象的任何访问都是未定义的行为。

此外,定义为多个翻译单元的静态持续时间对象的初始化顺序也是未定义的。您无法在代码中请求编译器在另一个对象之前或之后初始化一个静态对象,因为一个对象依赖于另一个对象。实际上你不能这样做。由编译器决定首先初始化哪个对象;特别是这实际上取决于编译每个源文件的顺序。

示例 -分段错误

// main.cpp
#include "src1.h"
A a{ 10 };      // declaring an object of class A with static duration.
int main() {}

// src1.cpp
#include "src1.h"
#include "src2.h"
B b{ 20 };      // declaring an object of class B with static duration.
A::A(int x): m_x(x) { b.f(); }

//src2.cpp
#include "src2.h"
int B::f() { return m_x; }
B::B(int x):  m_x(x) { }

//src1.h
struct A { 
    private: int m_x;
    public: A(int); 
};

//src2.h
struct B { 
    private: int m_x;
    public: B(int); int f(); 
};

g++ main.cpp src1.cpp src2.cpp // OK: main.cpp should be compiled first
g++ main.cpp src2.cpp src1.cpp // OK: main.cpp should be compiled first
g++ any_other_order // sigfault

解决方法:

constinit在 C++20 中引入

于 2021-12-06T16:33:37.087 回答