Ant*_*hov 9 c++ static-methods null-pointer undefined-behavior language-lawyer
我正在阅读一篇关于nullptrC++ 中一些特性的文章,一个特定的例子在我的理解中引起了一些混乱。
考虑(来自上述帖子的简化示例):
struct A {
void non_static_mem_fn() {}
static void static_mem_fn() {}
};
A* p{nullptr};
/*1*/ *p;
/*6*/ p->non_static_mem_fn();
/*7*/ p->static_mem_fn();
Run Code Online (Sandbox Code Playgroud)
根据作者的说法/*1*/,取消引用 the 的表达式nullptr本身不会导致未定义的行为。与/*7*/使用nullptr-object 调用静态函数的表达式相同。
理由基于C++ Standard Core Language Closed Issues, Revision 100中的issue 315
...
*pis not an error whenpis null 除非左值被转换为右值(7.1 [conv.lval]),它不在这里。
从而区分/*6*/和/*7*/。
因此,对实际的间接引用nullptr 不是未定义行为(在SO答案,在C ++标准的问题232讨论,...)。因此,/*1*/在这个假设下, 的有效性是可以理解的。
但是,如何/*7*/保证不引起UB呢?根据引用的引用,在 中没有从左值到右值的转换p->static_mem_fn();。但同样适用于/*6*/ p->non_static_mem_fn();,我认为我的猜测得到了同一期 315 中关于以下内容的引用:
/*6*/在 12.2.2 [class.mfct.non-static] 中明确指出为未定义,尽管有人可能会争辩说,因为它non_static_mem_fn();是空的,所以没有左值-> 右值转换。
(在引用中,我更改了“which”并f()获得与此问题中使用的符号的联系)。
那么,为什么这样的区分做出了p->static_mem_fn();和p->non_static_mem_fn();关于UB的因果关系?是否有意使用从可能是的指针调用静态函数nullptr?
附录:
nullptr是未定义的行为。虽然我同意在大多数情况下这是一个坏主意,但我不认为根据此处的链接和引号,该声明是绝对正确的。nullptr取消引用问题的问题。也许我错过了一些明显的答案。此答案中的标准引用来自 C++17 规范 (N4713)。
您的问题中引用的部分之一回答了非静态成员函数的问题。[class.mfct.非静态]/2:
如果为不是 类型或派生类型的
X对象调用类的非静态成员函数,则行为未定义。XX
例如,这适用于通过不同的指针类型访问对象:
std::string foo;
A *ptr = reinterpret_cast<A *>(&foo); // not UB by itself
ptr->non_static_mem_fn(); // UB by [class.mfct.non-static]/2
Run Code Online (Sandbox Code Playgroud)
空指针不指向任何有效对象,因此它当然也不指向该类型的对象A。使用你自己的例子:
p->non_static_mem_fn(); // UB by [class.mfct.non-static]/2
Run Code Online (Sandbox Code Playgroud)
既然如此,为什么这在静态情况下有效呢?让我们将标准的两个部分放在一起:
[expr.ref]/2:
...表达式
E1->E2转换为等效形式(*(E1)).E2...
[class.static]/1(强调我的):
...静态成员可以使用类成员访问语法来引用,在这种情况下将评估对象表达式。
特别是第二个块表示即使对于静态成员访问也会评估对象表达式。例如,如果它是具有副作用的函数调用,则这一点很重要。
放在一起,这意味着这两个块是等效的:
// 1
p->static_mem_fn();
// 2
*p;
A::static_mem_fn();
Run Code Online (Sandbox Code Playgroud)
因此,要回答的最后一个问题是当为空指针值时是否*p 单独存在未定义行为。p
传统观点会说“是”,但事实并非如此。 标准中没有任何内容表明单独取消引用空指针是 UB,并且有几个直接支持这一点的讨论:
*p明确指出当结果未使用时不是 UB。围绕取消引用空指针的未定义行为存在一些核心问题。其意图似乎是取消引用已明确定义,但使用取消引用的结果将产生未定义的行为。这个主题太混乱了,不能作为未定义行为的参考示例,或者如果要保留它,应该更准确地说明。
*p为 空指针时的定义行为p(只要不使用结果)。综上所述:
p->non_static_mem_fn(); // UB by [class.mfct.non-static]/2
p->static_mem_fn(); // Defined behavior per issue 232 and 315.
Run Code Online (Sandbox Code Playgroud)