bool、int 或其他堆栈变量的 NullReferenceException

NullReferenceException on bool, int, or other stack variable

首先:这个post的标题与我的实际问题不符。
但我也提供了原始问题的答案(bool 上的 NullRefExcp),因此其他用户将通过所选标题在这里找到它的解决方案。

我有一个class,类似下面的:

ref class CTest
{
  bool m_bInit;

  void func()
  {
    if (!m_bInit)
      return;
    ...
  }
  ...
}

今天我遇到了 func 虽然之前已经成功执行了很多次,但在某个时候崩溃并出现 NullReferenceException 的问题。
异常发生在行 if (!m_bInit)!
我知道,你们现在都在说,这是不可能的。但它实际上是这条线。原因如下:
我有两个不同的变量,都命名为 oTest,但位于不同的位置。其中之一已初始化:oTest = gcnew CTest。在此 oTest 上调用 func 效果很好。对另一个 oTest 的 func 的第一次调用失败,但出现上述异常。奇怪的是,崩溃似乎发生在 m_bInit 的查询中,异常的堆栈跟踪也说明了这一点。但这只是第一个调用未初始化 object 成员(它仍然是 nullptr)的地方。

因此,对其他有相同问题的用户的建议:向后检查堆栈以找到 object 上的函数调用,即 nullptr/null.

我现在的问题是:
为什么在第一次调用 nullptr 的 oTest 函数时执行不会失败?
为什么直到第一次访问某个成员才进入并执行该功能?

实际上,在我的例子中,输入了 3 个函数,并在堆栈和堆上创建了几个变量...

此代码:

 void func()
 {
    if (!m_bInit)
      return;
    ...
 }

实际上可以写成:

void func()
{
    if (!this->m_bInit)
        return;
    ...
}

希望您现在可以看出问题出在哪里。

成员函数调用只是一个常规函数调用,隐式包含 this 参数(它与其他参数一起传递)。

C++/CLI 编译器在调用非虚函数时不会执行 nullptr 检查 - 它会发出 call MSIL opcode.

在 C# 中实际上不是这种情况,因为 C# 编译器即使对于非虚函数也会发出 callvirt MSIL opcode。此操作码强制 JIT 对目标实例执行 null 检查。在 C# 中出现此错误的唯一方法是通过反射调用函数或生成您自己的使用 call 操作码的 IL。