考虑以下代码:
#include <iostream>
struct foo
{
// (a):
void bar() { std::cout << "gman was here" << std::endl; }
// (b):
void baz() { x = 5; }
int x;
};
int main()
{
foo* f = 0;
f->bar(); // (a)
f->baz(); // (b)
}
我们预计 (b)
会崩溃,因为空指针没有对应的成员 x
。在实践中,(a)
不会崩溃,因为从未使用过 this
指针。
因为 (b)
取消引用 this
指针 ((*this).x = 5;
),而 this
为 null,程序进入未定义的行为,因为取消引用 null 总是被认为是未定义的行为。
(a)
会导致未定义的行为吗?如果两个函数(和 x
)都是静态的呢?
最佳答案
(a)
和 (b)
都会导致未定义的行为。通过空指针调用成员函数始终是未定义的行为。如果函数是静态的,它在技术上也是未定义的,但存在一些争议。
首先要了解的是为什么取消引用空指针是未定义的行为。在 C++03 中,这里实际上有一些歧义。
尽管“取消引用空指针会导致未定义的行为” 在 §1.9/4 和 §8.3.2/4 的注释中都提到过,但从未明确说明过。 (注释是非规范性的。)
但是,可以尝试从 §3.10/2 中推断出来:
An lvalue refers to an object or function.
取消引用时,结果是一个左值。空指针不指向一个对象,因此当我们使用左值时,我们有未定义的行为。问题是上一句从来没有陈述过,那么“使用”左值是什么意思呢?甚至只是生成它,还是在更正式的意义上使用它来执行左值到右值的转换?
无论如何,它绝对不能转换为右值(第 4.1/1 节):
If the object to which the lvalue refers is not an object of type T and is not an object of a type derived from T, or if the object is uninitialized, a program that necessitates this conversion has undefined behavior.
这绝对是未定义的行为。
歧义来自于是否遵循但不使用来自无效指针的值的未定义行为(即,获取左值但不将其转换为右值)。如果不是,则 int *i = 0; *一世; &(*i);
定义明确。这是 active issue .
所以我们有一个严格的“取消引用空指针,获得未定义的行为” View 和一个弱的“使用取消引用的空指针,获得未定义的行为” View 。
现在我们考虑这个问题。
是的,(a)
会导致未定义的行为。事实上,如果 this
为 null,那么 无论函数的内容如何,结果都是未定义的。
这来自第 5.2.5/3 节:
If
E1
has the type “pointer to class X,” then the expressionE1->E2
is converted to the equivalent form(*(E1)).E2;
*(E1)
将导致严格解释的未定义行为,.E2
将其转换为右值,使其成为弱解释的未定义行为。
这也表明它是直接来自 (§9.3.1/1) 的未定义行为:
If a nonstatic 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.
对于静态函数,严格解释与弱解释会有所不同。严格来说是未定义的:
A static member may be referred to using the class member access syntax, in which case the object-expression is evaluated.
也就是说,它的评估就像它是非静态的一样,我们再次使用 (*(E1)).E2
.
但是,由于 E1
没有在静态成员函数调用中使用,如果我们使用弱解释,则调用是明确定义的。 *(E1)
产生一个左值,静态函数被解析,*(E1)
被丢弃,函数被调用。没有左值到右值的转换,所以没有未定义的行为。
在 C++0x 中,从 n3126 开始,歧义仍然存在。现在,请注意安全:使用严格的解释。
关于c++ - 何时在空实例上调用成员函数会导致未定义的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2474018/