【问题标题】:Constant evaluation of self-assignment in member initialization在成员初始化中不断评估自赋值
【发布时间】:2022-10-02 04:13:00
【问题描述】:

在下面的程序中,constexpr 函数foo() 使用字段x=1 生成A 的对象,然后在其之上使用std::construct_at 和默认初始化x=x 构造另一个对象,然后是常量评估值打印:

#include <memory>
#include <iostream>

struct A {
    int x = x;
};

constexpr int foo() {
    A a{1};
    std::construct_at<A>(&a);
    return a.x;
}

constexpr int v = foo();

int main() {
    std::cout << v;
}

GCC 在这里打印1。 Clang 和 MSVC 都打印 0。只有 Clang 发出警告:field \'x\' is uninitialized when used。演示:https://gcc.godbolt.org/z/WTsxdrj8e

程序中是否存在未定义的行为?如果是,为什么在持续评估期间没有编译器检测到它?如果不是,哪个编译器是正确的?

  • 你做(直接)list initialization 的聚合(导致aggregate initialization),这将copy initialize 成员x。所以默认初始化不应该发生。似乎 GCC 是正确的,而其他的都是错误的。
  • @Someprogrammerdude 在您描述的 UB 之后有 std::construct_at&lt;A&gt;(&amp;a);。 @OP 编译器不是万能的,这里的 UB 隐藏在 construct_at 下。最近在 SO 上还有一个问题,编译器不会在 constexpr 函数中的 constexpr 对象上的 construct_at 上说任何话。
  • 有什么理由相信这与 stackoverflow.com/q/70820127/7325599gcc.gnu.org/bugzilla/show_bug.cgi?id=104192 不同。它仍然看起来涉及不确定值的左值到右值转换(现在在初始化而不是在返回中),另一个 SO 答案暗示这是 IFNDR。因此不需要诊断。
  • 在另一个问题中,Clang 和 MSVC 以 expression did not evaluate to a constant 错误拒绝该程序,并且这里所有编译器都接受该代码,尽管产生了不同的结果。

标签: c++ language-lawyer undefined-behavior constexpr


【解决方案1】:

C++20 [basic.life]/1.5 声明对象(在本例中为对象a)的生命周期在以下时间结束

对象占用的存储空间被释放,或被未嵌套在o (6.7.2) 中的对象重用。

该标准并不完全清楚何时将内存视为“重用”(因此,旧的A 的生命周期结束)但 [intro.object]/1 指出

... 一个对象在其构建期间 (11.10.5)、整个生命周期 (6.7.3) 和销毁期间 (11.10.5) 占据一个存储区域。

在我看来,默认成员初始化器 = x 的评估是在新 A 对象的“构造期间”发生的,这意味着此时新的 A 对象已经到来存在(但它的生命周期尚未开始),并且旧对象的生命周期已经结束。这意味着新的A 的初始化读取其x 成员的值,该成员的生命周期尚未开始,因为它的初始化未完成,这违反了 [basic.life]/7.1 并且将是 UB。

在 C++20 中,foo 的定义违反了 [dcl.constexpr]/6:

既不是默认值也不是模板的 constexpr 函数是格式错误的,不需要诊断,如果在评估任何有效的明显常量评估表达式时无法执行对函数调用的评估。

这意味着编译器不需要为您的程序发出诊断。

在 C++23 中,该规则将被废除(请参阅 P2448),因此您可以争辩说,如果编译器声称符合 C++23,则必须发出诊断。然而,没有一个编译器能够在常量表达式中诊断出所有类型的核心语言 UB(例如,似乎特别难以诊断的是无序写入或涉及相同标量对象的无序读写),所以不要持有你的呼吸让它得到修复。

【讨论】:

    猜你喜欢
    • 2019-01-05
    • 2014-05-25
    • 2019-07-29
    • 2017-04-03
    • 2019-09-10
    • 2011-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多