【问题标题】:C++11 strange behavior with classes, pointers and global scope declarationsC++11 类、指针和全局范围声明的奇怪行为
【发布时间】:2015-04-10 13:29:40
【问题描述】:
[Global Scope]

myClass *objA, *objB, *obj;
int objnum;

我想在objA 和objB 之间切换并将它们分配给obj,所以在main() 我有:

int main()
{
  objA = new myClass(parameters...);
  objB = new myClass(parameters...);

  // start with objA;
  objnum = 0;
  obj = objA;
}

有时会调用一个在两个对象之间切换的函数:

void switchObjects()
{
  if (++objnum > 1) objnum = 0;
  obj = objnum == 0 ? objA : objB;
}

在我使用对象的函数中,我有:

void doYourJob()
{
  int res = obj->work();
}

现在奇怪的是,如果我不将 obj 分配给 objA 或 objB,它仍然有效。相反,我希望有一个例外。即使我这样做obj = NULL;,它仍然有效!这是什么巫术?

好的,我可以提供一个不同的示例,它会带来相同的结果,而不使用 NULL 指针:

myClass *obj[2];
int objnum;

void switchObject()
{
  if (++objnum > 1) objnum = 0;
}

void doYourJob()
{
  res = obj[objnum]->work();
}

int main()
{
  obj[0] = new myClass(parameters...);
  obj[1] = new myClass(parameters...);

  objnum = 0;
}

使用上面的代码,无论 objnum 的值如何,我仍然可以让两个对象一起工作,即使我只在一个实例上调用 work()。

如果我用这个替换函数doYourJob():

void doYourJob()
{
  int res1 = obj[0]->work();
  int res2 = obj[1]->work();
}

我总是得到翻倍的结果,就好像我对每个对象调用函数 work() 两次一样。

【问题讨论】:

  • 你不能期望未定义的程序有任何东西。
  • 在空指针上调用成员函数是未定义的行为。如果成员函数实际上不使用任何类成员,它通常会起作用。
  • 我发布了一个与空指针无关的不同示例,任何人都可以给我一个线索吗?

标签: c++ class pointers c++11


【解决方案1】:

考虑一个更简单的例子:

#include <iostream>

struct X
{
    void foo() { std::cout << "Works" << std::endl; }
};

int main() {
    X* x = nullptr;
    x->foo();
}

在大多数编译器和大多数平台上,尽管在空指针上调用了foo,但这段代码似乎可以正常工作。但是,该行为在技术上是未定义。也就是说,C++ 语言对这样做可能发生的事情没有任何限制。

为什么有效?好吧,调用成员函数只需要知道它被调用的对象的类型。我们知道x 指向X,所以我们知道要调用什么函数:X::foo。在许多情况下,可能很难甚至不可能知道指针是否指向真实对象,因此编译器只是让它发生。在这种情况下,函数的主体实际上并不依赖于实际存在的X 对象,因此它可以正常工作。不过,这不是您可以依赖的。

【讨论】:

  • 我已经用一个不同的例子更新了我的帖子,它给出了相同的结果。你能看看吗?它仍然与空指针有关吗?
  • @MarkMiles Can't reproduce。您需要发布一个带有简短可编译示例的新问题,以供任何人帮助。
  • 好吧,我也无法在更简单的例子中重现它......我的实际程序要大得多,涉及许多内存分配、计时器、回调、套接字、实时音频等。 . 问题可能出在其他地方。我试图在这个例子中简化它(ideone.com/bjQ1s8),但在我的实际程序中,无论我使用类指针使用什么索引,我都没有收到任何错误,它仍然有效。
  • @MarkMiles 该程序的输出有什么您不期望的吗?正如我所说,如果你在指向无效对象的指针上调用成员函数,你会得到未定义的行为。它可能看起来有效。你不应该期待一个错误。
  • @MarkMiles 对不起,still can't reproduce!如果您不知道如何简化它,我只能建议您跟踪您的程序或在其上运行调试器。
猜你喜欢
  • 2014-09-11
  • 1970-01-01
  • 1970-01-01
  • 2020-12-10
  • 1970-01-01
  • 1970-01-01
  • 2020-11-28
  • 2012-05-29
  • 1970-01-01
相关资源
最近更新 更多