繁体   English   中英

是否允许在默认成员初始化程序中调用非静态成员 function?

[英]Is it allowed to call a non-static member function in a default member initializer?

考虑这个 class:

#include <iostream>

struct foo {
    int a = 42;
    int b = bar();
    int bar() { return a; }
};

int main(){
    foo f;
    std::cout << f.a << " " << f.b;
}

它打印预期的42 42 标准是否允许在默认成员初始化程序中调用成员 function?

以下我希望是未定义的:

struct broken {
    int a = bar();
    int b = 42;       
    int bar() { return b; }
};

不幸的是,它编译时没有警告

如您所见,这是合法的,但很脆弱,不推荐。 当您为 class 成员指定默认初始化程序时,这些只是在 class 成员初始化程序列表中使用此值的语法糖。 因此,如果我们查看何时可以调用成员 function,我们会发现[class.cdtor]/1[class.cdtor]/4声明:

1) 对于具有非平凡构造函数的 object ,在构造函数开始执行之前引用 object 的任何非静态成员或基 class 会导致未定义的行为 对于具有非平凡析构函数的 object,在析构函数完成执行后引用 object 的任何非静态成员或基 class 会导致未定义的行为。

4)成员函数,包括虚函数([class.virtual]),可以在构造或销毁([class.base.init])期间调用。[...]

强调我的

由于构造函数已经开始执行,并且我们被允许调用成员函数,我们不在 UB 领域。

接下来我们要考虑的是构造顺序,因为成员依赖于它。 该信息在[class.base.init]/13

然后,非静态数据成员按照它们在 class 定义中声明的顺序进行初始化(同样不管 mem 初始化程序的顺序)。

因此,成员是按照它们在 class 中声明的顺序构建的,这意味着在您的第一个示例中,您在初始化之后引用a ,因此您不在 UB 土地中。

在您的第二个示例中,您指的是尚未初始化的 object 并且读取未初始化对象的值是未定义的行为。

标准在这里说:

可以为正在构建的 object 调用成员函数(包括虚拟成员函数,[class.virtual])。 类似地,正在构建的 object 可以是 typeid 运算符 ([expr.typeid]) 或 dynamic_cast ([expr.dynamic.cast]) 的操作数。 但是,如果这些操作在基类的所有 mem-initializer 完成之前在 ctor-initializer(或直接或间接从 ctor-initializer 调用的 function 中)中执行,则程序具有未定义的行为。

由于您没有基类,因此即使正在构建成员函数也可以调用broken a将被初始化为不确定的值。

我有点为时过早。 如在另一个答案中所见,存在问题,function 从未定义行为的未初始化值读取。 所以不是这个 function 本身的调用,而是它所做的是 UB。

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM