简体   繁体   English

为什么半初始化结构的 constinit 不起作用

[英]Why constinit of half-initialized struct does not work

struct A1 { int x;     int y; };
struct A2 { int x = 1; int y = 2; };
struct A3 { int x = 1; int y; };

constinit A1 a1; // x == 0, y == 0.
constinit A2 a2; // x == 1, y == 2.
          A3 a3; // x == 1, y == 0.
constinit A3 a4; // Error: illegal initialization of 'constinit' entity with a non-constant expression

int main() {}

What is the problem with a4 ? a4有什么问题? I mean a4.x should be initialized by a constant 1 (same as for a2 where it works) and a4.y by a constant 0 because a4 is a global static variable (same as for a1 where it works).我的意思是a4.x应该由常量1初始化(与它工作的a2相同)和a4.y由常量0初始化,因为a4是全局 static 变量(与它工作的a1相同)。

Now, considering that both MSVC and GCC fail to compile this code I assume the standard somehow forbids it.现在,考虑到 MSVC 和 GCC 都无法编译这段代码,我假设标准以某种方式禁止它。 But any way I look at a4 its initial value is exact, constant and known at compile time so why the standard forbids us from declaring it as constinit )?但无论如何我看a4它的初始值是准确的,常量并且在编译时已知所以为什么标准禁止我们将它声明为constinit )?

In addition to this, clang++ also rejects the first constinit ialization:除此之外, clang++还拒绝了第一个constinit ialization:

error: variable does not have a constant initializer
constinit A1 a1;  // x == 0, y == 0.

I think this is a case where we might be missing some wording.我认为在这种情况下,我们可能会遗漏一些措辞。

To start with, there are three stages of initialization that happen ( [basic.start.static] ):首先,初始化分为三个阶段( [basic.start.static] ):

  1. Constant initialization常量初始化
  2. If not that, zero-initialization (for static storage duration variables, like the ones in this question)如果不是那样,则零初始化(对于 static 存储持续时间变量,如本问题中的变量)
  3. If necessary, dynamic initialization如有必要,动态初始化

(1) and (2) together are static initialization, (3) is... well, dynamic. (1) 和 (2) 一起是 static 初始化,(3) 是……好吧,动态的。 And what constinit does is ensure that there is no dynamic iniitialization, from [dcl.constinit] : constinit所做的是确保没有来自[dcl.constinit]的动态初始化:

If a variable declared with the constinit specifier has dynamic initialization ([basic.start.dynamic]), the program is ill-formed.如果用constinit说明符声明的变量具有动态初始化 ([basic.start.dynamic]),则程序格式错误。

And the rule for constant initialization is, from [expr.const] :常量初始化规则来自[expr.const]

A variable or temporary object o is constant-initialized if变量或临时 object o常量初始化的,如果

  • either it has an initializer or its default-initialization results in some initialization being performed, and它要么有一个初始化器,要么它的默认初始化导致执行一些初始化,并且
  • the full-expression of its initialization is a constant expression when interpreted as a constant-expression , except that if o is an object, that full-expression may also invoke constexpr constructors for o and its subobjects even if those objects are of non-literal class types.当解释为常量表达式时,其初始化的完整表达式是一个常量表达式,除非o是 object,该完整表达式也可以为o及其子对象调用 constexpr 构造函数,即使这些对象是非文字的class 种。

With that said, let's go through the three types.话虽如此,让我们通过三种类型来了解 go。 Starting with the easiest:从最简单的开始:

struct A2 { int x = 1; int y = 2; };
constinit A2 a2; // x == 1, y == 2.

Here, we're initializing all the members, this is clearly constant initialization.在这里,我们正在初始化所有成员,这显然是常量初始化。 Not really much of a question here.这里不是一个真正的问题。

Next:下一个:

struct A1 { int x;     int y; };
constinit A1 a1; // x == 0, y == 0.

Here, our default constructor does... nothing, there is no initialization.在这里,我们的默认构造函数没有...什么都没有,没有初始化。 So this is not constant initialization.所以这不是常量初始化。 But zero-initialization happens and then there is no further initialization.但是零初始化发生了,然后就没有进一步的初始化了。 There is certainly no dynamic initialization that has to take place here, so there is nothing for constinit to diagnose.这里肯定没有必须进行的动态初始化,所以constinit没有什么可以诊断的。

Lastly:最后:

struct A3 { int x = 1; int y; };
constinit A3 a4; // Error: illegal initialization of 'constinit' entity with a non-constant expression

Prior to the adoption of P1331 , this initialization of a4 was clearly not constant initialization because constant initialization explicitly required fully initialized variables.在采用P1331之前, a4的这种初始化显然不是常量初始化,因为常量初始化明确需要完全初始化的变量。 But we don't have this requirement anymore, the rule was moved later - to when a4.y would actually be read.但是我们不再有这个要求了,规则后来被移动了 - 到实际读取a4.y的时候。

But I think the intent in this case is very much that a4 is not constant initialized, due to it being partially uninitialized.但我认为在这种情况下的意图是a4不是常量初始化,因为它部分未初始化。 This probably merits a core issue.这可能值得一个核心问题。

Given that it is not constant initialization, then we go into zero initialization.鉴于不是常量初始化,那么我们把go改成零初始化。 But after that, a4 still isn't fully initialized - because we have to set x to 1 .但在那之后, a4仍然没有完全初始化——因为我们必须将x设置为1 There is no provision for half-constant half-zero initialization.没有提供半常数半零初始化。 The rule is constant or, if not that, zero.规则是不变的,或者如果不是那样,则为零。 Since this isn't (or, at least, shouldn't be) constant initialization, and zero-initialization is insufficient, a4 must undergo dynamic initialization.由于这不是(或者至少不应该是)常量初始化,并且零初始化是不够的,因此a4必须进行动态初始化。 And thus, constinit should flag this case.因此, constinit应该标记这种情况。 gcc and msvc are correct here (clang erroneously rejects a1 ). gcc 和 msvc 在这里是正确的(clang 错误地拒绝a1 )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么 constinit 允许 UB? - Why does constinit allow UB? 为什么此结构填充技巧起作用? - Why does this struct padding trick work? 为什么结构化绑定在struct上不能按预期工作? - Why does structured binding not work as expected on struct? 为什么在 C++ 中未初始化数组中有随机数,而在半初始化数组的未初始化成员中没有? - Why there are Random numbers in non initialized array but not in non initialized members of half initialized array in C++? 为什么此结构用字段中已有的数据初始化? - Why is this struct initialized with data already in a field? 为什么 C 结构破解不适用于 C++ 模板声明? - Why does the C struct hack not work for C++ template declarations? C++ - 为什么聚合初始化不适用于模板结构 - C++ - Why does aggregate initialization not work with template struct 为什么静态const char * template struct成员未初始化 - Why is static const char * template struct member not initialized 为什么要编译(在初始化之前用于函数)? - Why does this compile (used in function before initialized)? 初始化结构的指定初始化 - Designated initialization of initialized struct
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM