我的假设是下面的代码不正确的NDR?但为什么

My assumption is that the code below ill-formed NDR? But why?

本文关键字:NDR 为什么 不正确 代码 我的 假设      更新时间:2023-10-16

[class.mem]/6:

班级的完整上下文是
(6.1)功能主体,
(6.2) 默认参数,
(6.3)noexcept特征器([[excep.spec]),
(6.4) 合同条件,
(6.5)默认成员ritializer

在 班级成员规范。[注意:一个完整的上下文 嵌套类也是任何封闭的完整上下文 类,如果嵌套类是在成员规格中定义的 封闭班级。 - 终注]

上面突出显示的文本似乎为以下片段提供了支持:

#include<iostream>
struct A{
    int i = j + 1;
    int j = 1;
};
int main(){
    A a;
    std::cout << a.i << 'n';
    std::cout << a.j << 'n';
}

,我期望它可以打印

2
1

GCC和Clang Print

1
1

但此外,Clang给出以下警告:

prog.cc:3:13: warning: field 'j' is uninitialized when used here [-Wuninitialized]
    int i = j + 1;
            ^
prog.cc:8:7: note: in implicit default constructor for 'A' first required here
    A a;
      ^
prog.cc:2:8: note: during field initialization in the implicit default constructor
struct A{
       ^
1 warning generated.

我的假设是代码是不形成型的NDR。但是为什么?

您的代码由于[class.base.init]/9

而具有未定义的行为

在非级别的构造函数中,如果给定潜在构造的子对象不是由mem-initializer-id指定的(包括没有mem-initialial-list列表的情况,因为构造函数没有ctor-initialializer),则

  • 如果该实体是具有默认成员初始化器([class.mem])的非静态数据成员,则

    [...]构造函数的类不是联合[...]

    该实体是根据[dcl.init]中指定的默认成员初始化器初始化的。

所以,这意味着

struct A{
    int i = j + 1;
    int j = 1;
};

被翻译成

struct A{
    A() : i(j + 1), j(1) {}
    int i;
    int j;
};

,并且由于i首先是初始化的,因此它使用了一个非初始化的变量,并且是未定义的行为。

我认为代码等于以下:

struct A{
    int i;
    int j;
    A():i(j + 1),j(1){}
};

这表明编译器是正确的。因为成员按顺序(标准*中的某个地方说明)初始化。原始声明初始化应该只是所有CTOR中初始化的句法糖。因此,该代码确实具有不确定的行为,因为j是一个非初始化的变量。

编辑: *找到了[10.9.2初始化基础和成员](http://eel.is/c draft/class.base.init)

在非规定的构造函数中,初始化按以下顺序进行:

(13.1) 首先,仅对于最派生的类的构造函数([Into.Object]),虚拟基类是按照它们出现在深度优先的左右横向遍历的顺序的初始初始化的。其中"从左到右"是派生的类基准列表中基类的外观顺序。

(13.2) 然后,直接基类以声明顺序初始化,因为它们出现在基本列表中(无论mem-initializers的顺序如何)。

(13.3) 然后,非静态数据成员以在类定义中声明的顺序初始化(再次不论MEM-INITIALIZERS的顺序)。

(13.4) 最后,执行构造函数的复合态。

这里的问题是在声明和初始化j。

之前使用int i = j + 1

您应该做的是

struct A{ int j = 1; int i = j + 1; };

因此,应在i之前初始化j。希望这会有所帮助:)

在您给出的变量j的示例中没有初始化(gcc也许是默认的这些this thise nor Initialized积分变量为0)这就是为什么i的初始值是1,因此打印了值顺便说一句,以这种方式初始化变量不是一个好主意。而是使用构造函数请参阅此