在 nullptr 上调用无状态类的非静态成员函数是否合法?

Adr*_*ian 2 c++ pointers member-functions language-lawyer

考虑以下代码:

int main()
{
    struct EmptyStruct{
        void nonstatic_mf() const { std::cout <<"EmptyStruct\n"; }
    };


    EmptyStruct *esptr = nullptr;
    esptr->nonstatic_mf(); 
}  
Run Code Online (Sandbox Code Playgroud)

这是一个合法的 C++(它似乎在 gcc 和 clang 中工作)?

Gui*_*cot 8

即使结构为空,它的大小也非零。必须有一些内存作为它的存储。

不,这始终是 UB。如果您不需要实例,请将其设为静态。静态函数仍然可以使用点.语法调用。

为什么?因为您不能取消引用空指针。调用与此等效的成员函数:

 EmptyStruct *esptr = nullptr;
 (*esptr).nonstatic_mf();
Run Code Online (Sandbox Code Playgroud)

如您所见,空指针是被延迟的,也就是UB。

标准对此有何规定?来自[class.mfct.non-static]/2

如果为非 X 类型或从 X 派生的类型的对象调用类 X 的非静态成员函数,则行为未定义。

空指针不指向 的有效实例EmptyStruct。仅此一项就足以使行为未定义

来自[expr.ref]/2

对于第一个选项(点),第一个表达式应为泛左值。对于第二个选项(箭头),第一个表达式应为具有指针类型的纯右值。表达式E1->E2被转换为等价形式(*(E1)).E2[expr.ref]的其余部分将仅解决第一个选项(点)。

Soesptr->nonstatic_mf()等效于(*esptr).nonstatic_mf(),并且取消引用空指针是未定义的行为。

所以有两种方式未定义此代码。