在 nullptr 上调用无状态 class 的非静态成员函数是否合法?
Is it legal to call a non-static member function of a stateless class on a nullptr?
考虑以下代码:
int main()
{
struct EmptyStruct{
void nonstatic_mf() const { std::cout <<"EmptyStruct\n"; }
};
EmptyStruct *esptr = nullptr;
esptr->nonstatic_mf();
}
这是合法的 C++ 吗(它似乎在 gcc 和 clang 中工作)?
即使该结构为空,它的大小也非零。肯定有一些内存作为它的存储。
没有。这始终是 UB。如果您不需要该实例,请将其设为静态。仍然可以使用点 .
语法调用静态函数。
为什么?因为您不能取消引用空指针。调用等效于此的成员函数:
EmptyStruct *esptr = nullptr;
(*esptr).nonstatic_mf();
可以看到,空指针是deferenced的,也就是UB
标准对此有何规定?来自 [class.mfct.non-static]/2:
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.
空指针不指向 EmptyStruct
的有效实例。仅此一项就足以使行为未定义
来自 [expr.ref]/2:
For the first option (dot) the first expression shall be a glvalue.
For the second option (arrow) the first expression shall be a prvalue having pointer type.
The expression E1->E2
is converted to the equivalent form (*(E1)).E2
; the remainder of [expr.ref] will address only the first option (dot).
所以 esptr->nonstatic_mf()
实际上等同于 (*esptr).nonstatic_mf()
,取消引用空指针是未定义的行为。
所以这段代码有两种未定义的方式。
考虑以下代码:
int main()
{
struct EmptyStruct{
void nonstatic_mf() const { std::cout <<"EmptyStruct\n"; }
};
EmptyStruct *esptr = nullptr;
esptr->nonstatic_mf();
}
这是合法的 C++ 吗(它似乎在 gcc 和 clang 中工作)?
即使该结构为空,它的大小也非零。肯定有一些内存作为它的存储。
没有。这始终是 UB。如果您不需要该实例,请将其设为静态。仍然可以使用点 .
语法调用静态函数。
为什么?因为您不能取消引用空指针。调用等效于此的成员函数:
EmptyStruct *esptr = nullptr;
(*esptr).nonstatic_mf();
可以看到,空指针是deferenced的,也就是UB
标准对此有何规定?来自 [class.mfct.non-static]/2:
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.
空指针不指向 EmptyStruct
的有效实例。仅此一项就足以使行为未定义
来自 [expr.ref]/2:
For the first option (dot) the first expression shall be a glvalue. For the second option (arrow) the first expression shall be a prvalue having pointer type. The expression
E1->E2
is converted to the equivalent form(*(E1)).E2
; the remainder of [expr.ref] will address only the first option (dot).
所以 esptr->nonstatic_mf()
实际上等同于 (*esptr).nonstatic_mf()
,取消引用空指针是未定义的行为。
所以这段代码有两种未定义的方式。