Bizzare nullref in C++

Bizzare nullref in C++

本文关键字:C++ in nullref Bizzare      更新时间:2023-10-16

我有一小段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"和"this->Target"为非空。

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

// From this.
virtual void Stop();
// To this.
void Stop();

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

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

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