-1

可能重复:
何时在空实例上调用成员函数会导致未定义的行为?

像这样的任何东西:

class Class {
public:
    void Method()
    {
       //empty;
    }
};

Class* object = 0;
object->Method();

在 C++ 中是未定义的行为,因为通过空指针调用非静态成员函数在形式上是非法的。有关C++ 标准引用的详细解释,请参阅此答案。我很清楚理论部分,这个问题不是关于理论的,所以它不是那个问题的重复。

在所有实现中,我都知道上面的代码或其等效代码不会导致任何可观察到的问题 - 因为成员函数不访问对象,所以该方法将被很好地调用。

我可以有任何真实的例子,其中相同的设置会导致实际的可观察到的问题吗?

4

3 回答 3

4

简单的:

struct Object { void foo(); std::string s; };

void print(Object* o) {
  o->foo();
  if (o) { std::cout << o->x << "\n"; }
}

让我们说不访问(即)foo的任何非静态属性。Objectx

问题在于,如果为 null,则由于形式上 o->foo()是未定义的行为,因此很明显不是null。因此检查是多余的。oo

该功能因此得到优化:

void print(Object* o) {
  o->foo();
  std::cout << o->x << "\n";
}

颠倒顺序不会改变任何东西:

void print(Object* o) {
  if (o) { std::cout << o->x << "\n"; }
  o->foo();
}

仍在优化:

void print(Object* o) {
  std::cout << o->x << "\n";
  o->foo();
}

有时被一些 SO 成员称为未定义行为的时间旅行条款。

有关更多信息,请查看 Chris Lattner 关于未定义行为的系列:

您的具体问题已在 中解决2/3

这是否真的失败取决于您使用的编译器、您指定的优化传递以及它们运行的​​顺序。

真的想依赖所有这些 :x 吗?

当然,有人会争辩说,拥有一个不访问对象任何状态的函数成员是没有意义的......所以这个问题本身在实践中没有什么价值(但对于它的理论方面很有趣)。

于 2012-02-08T10:15:08.147 回答
1

这是UB,那么什么会构成“问题”?要成为一个问题,代码必须做一些标准规定它应该做或我们期望它做的事情之外的事情,否则它不是问题。标准让我们不知道代码应该或将要做什么,所以无论它做什么都不是问题。

你说它不会导致任何“可观察到的问题”。好吧,当然不是。不管做什么都会好的。它可能会出错,这不会是一个“问题”,因为这是标准告诉我们可能发生的事情。

于 2012-02-08T10:19:52.157 回答
0

这段代码不太可能在我知道的任何平台上产生任何问题。它仍然是未定义的行为,主要是因为它是一个不相关的极端情况:可以定义在某些条件下调用空指针上的成员函数是可以的。然而,有什么意义呢?如果您不访问任何成员,为什么要将该函数设为非静态成员函数?不定义这种情况没有任何损失,因为没有必要定义这种情况,因此会不必要地使语言复杂化。

于 2012-02-08T10:13:15.137 回答