gpt4 book ai didi

c++ - C++ 中的这种未定义行为是从悬空指针调用函数吗

转载 作者:塔克拉玛干 更新时间:2023-11-03 08:18:09 26 4
gpt4 key购买 nike

当指针悬空时,SO 上出现了一个问题,询问“为什么这样工作”。答案是它是 UB,这意味着它可能有效也可能无效。

我在教程中了解到:

#include <iostream>

struct Foo
{
int member;
void function() { std::cout << "hello";}

};

int main()
{
Foo* fooObj = nullptr;
fooObj->member = 5; // This will cause a read access violation but...
fooObj->function(); // Because this doesn't refer to any memory specific to
// the Foo object, and doesn't touch any of its members
// It will work.
}

这是否等同于:

static void function(Foo* fooObj) // Foo* essentially being the "this" pointer
{
std::cout << "Hello";
// Foo pointer, even though dangling or null, isn't touched. And so should
// run fine.
}

我错了吗?即使正如我所解释的那样只是调用一个函数而不访问无效的 Foo 指针,它是否是 UB?

最佳答案

您正在推理实践中发生的事情。允许未定义的行为做你期望的事情......但不能保证。

对于非静态情况,使用 [class.mfct.non-static] 中的规则可以直接证明:

If a non-static member function of a class X is called for an object that is not of type X, or of a type derived from X, the behavior is undefined.

请注意,没有考虑非静态成员函数是否访问*this。该对象只需要具有正确的动态类型,而 *(Foo*)nullptr 当然不需要。


特别是,即使在使用您描述的实现的平台上,调用

fooObj->func();

转换为

__assume(fooObj); Foo_func(fooObj);

并且优化不稳定。

这是一个与您的预期相反的示例:

int main()
{
Foo* fooObj = nullptr;
fooObj->func();
if (fooObj) {
fooObj->member = 5; // This will cause a read access violation!
}
}

在真实的系统上,这很可能以注释行的访问冲突结束,因为编译器使用了 fooObj can't be null 的事实fooObj->func() 以消除其后的 if 测试。

即使您认为自己了解平台的功能,也不要做不合理的事情。 Optimization instability is real.


此外,该标准比您想象的更加严格。这将导致 UB:

struct Foo
{
int member;
void func() { std::cout << "hello";}
static void s_func() { std::cout << "greetings";}
};

int main()
{
Foo* fooObj = nullptr;
fooObj->s_func(); // well-formed call to static member,
// but unlike Foo::s_func(), it requires *fooObj to be a valid object of type Foo
}

标准的相关部分可在[expr.ref]中找到:

The expression E1->E2 is converted to the equivalent form (*(E1)).E2

和随附的脚注

If the class member access expression is evaluated, the subexpression evaluation happens even if the result is unnecessary to determine the value of the entire postfix expression, for example if the id-expression denotes a static member.

这意味着有问题的代码肯定会评估 (*fooObj),试图创建对不存在对象的引用。已经有几个提议允许并且只禁止在这样的引用上允许左值->右值转换,但到目前为止这些都被拒绝了;在迄今为止的所有标准版本中,即使形成引用也是非法的。

关于c++ - C++ 中的这种未定义行为是从悬空指针调用函数吗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49213446/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com