C ++中的Bizzare nullref

时间:2016-11-30 21:34:09

标签: c++ c++11 pointers

我有一小段C ++代码让我疯了。每当它运行时,它会在非常意外的地方抛出一个空引用异常。

void CSoundHandle::SetTarget(CSound* sound)
{
  assert(_Target == nullptr);
  if (sound == nullptr) { return; }

  _Target = sound;

  // This works just fine.
  _Target->Play();

  // This is the code that throws the exception.  It doesn't seem possible, as
  // we should not be able to get here if 'sound' is null.
  _Target->Stop();
}

那到底是怎么回事?输出窗口中的消息是:

this->_Target-> was nullptr.
0xC0000005: Access violation reading location 0x00000014

我已经在反汇编中确认它也没有在Stop函数内部发生。这怎么可能?

编辑: 确实初始化了声音的指针,并且这个'和' this->目标'是非空的。

编辑2: 我通过稍微改变Stop函数的声明以某种方式解决了这个问题:

// From this.
virtual void Stop();

// To this.
void Stop();

这似乎特别奇怪,因为Play()也是虚拟的,但是没有任何麻烦。我不能说我以前见过这样的事情。没有其他名为' Stop'在程序的其余部分,也没有CSound的子类,所以我有点困惑。

1 个答案:

答案 0 :(得分:3)

读取位置0x00000014意味着您正在尝试从对象的开头访问位于0x14字节的字段。指向该对象的指针设置为null。所以问题出在函数的调用者身上:它传递一个指向sound的错误指针,它既不是null也不是有效的。这就是为什么函数中的空检查通过(0x14不为空),但你仍然崩溃。

更新: 对问题的第二次编辑表明问题在于调用虚函数。这里的null是虚拟指针,0x14是Stop虚函数的偏移量。在对象构造期间设置虚拟指针(在编译器生成的代码中),并且永远不应该指向0.如果是,则程序的某些部分正在破坏对象。一个易于检测的情况是尝试重置对象,但内存损坏(例如,对数组的越界写入)也可能导致此问题。