【问题标题】:Can dangling pointer be equal to valid pointer during constant evaluation in C++?在 C++ 中的常量评估期间,悬空指针可以等于有效指针吗?
【发布时间】:2021-11-27 07:44:31
【问题描述】:

在 C++17 中的常量表达式求值期间,编译器是否应考虑任何指向有效对象的指针与任何指向其生命周期结束后的对象的指针不同?

例如:

constexpr auto f(int * x = nullptr) {
    int c = 0;
    auto p = &c;
    if ( x == p )
        throw "unexpected";
    return p;
};

int main() {
    static_assert( f( f() ) );
}

这里函数f()的内部调用返回一个悬空指针,再次传递给f。我相信条件x == p 一定是false,因为x 是一个悬空指针,p 是一个有效指针,在Clang 中确实如此。但在 GCC 中,条件得到满足,并且由于throw 而不断评估失败。演示:https://gcc.godbolt.org/z/ehcMro17q

这是未定义的或实现定义的行为,还是其中一个编译器有误?

【问题讨论】:

  • 这是一个更简单的 MWE,它暴露了相同的行为,据我所知:gcc.godbolt.org/z/sbsK6x775
  • AFAIK 返回指向局部变量的指针是未定义的行为,因此任何事情都可能发生。

标签: c++ c++17 language-lawyer constexpr dangling-pointer


【解决方案1】:

悬空指针与任何其他指针的比较结果是实现定义的:

当一个存储区域的持续时间结束时,表示该存储区域任何部分地址的所有指针的值都变为无效指针值。 […] 任何其他对无效指针值的使用都具有实现定义的行为。

([basic.stc]/4)(平等比较包含在此处的“其他用途”中。)

如 cmets 中所述,即使是比较操作数的左值到右值转换也会为无效指针 ([conv.lval]/3.3) 调用实现定义的行为。不幸的是,我找不到任何要求对相等比较的操作数进行左值到右值转换的东西; [expr.eq]/2 充其量只是非常间接地暗示了这一点。

【讨论】:

  • 在与无效的指针值比较之前,需要先获取。但是,应用于表示包含无效指针值的对象的左值到右值的转换甚至不能保证产生无效的指针值。
  • 如 cmets 中所述,即使调用 f(f()) 本身也已经从无效指针的左值到右值转换调用了实现定义的行为。我相信即使比较本身也是如此......我不明白,你认为我的意思是不是==操作数的转换? f(f()) 表达式本身没有 L2R 转换。 我找不到任何要求对相等比较的操作数进行左值到右值转换的东西一个已知的缺陷。
  • @LanguageLawyer 确实,f(f()) 的事情是脑放屁。我不确定您是否指的是比较操作数,正是因为我无法在标准中找到提及。你碰巧提到了缺陷讨论吗?
  • 你碰巧有参考缺陷讨论吗?你想要什么样的讨论?未公开 CWG 会议速记?关于它的内容不多。来自标准讨论邮件列表的内容?你可以看看this
  • 真的是我自己的错。应该知道不如搞鸽子棋。
猜你喜欢
  • 1970-01-01
  • 2011-07-14
  • 2021-10-02
  • 2022-11-10
  • 2017-06-19
  • 1970-01-01
  • 2020-09-07
  • 2019-03-31
相关资源
最近更新 更多