【问题标题】:NullReferenceException on bool, int, or other stack variablebool、int 或其他堆栈变量上的 NullReferenceException
【发布时间】:2015-01-14 13:48:23
【问题描述】:

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

我有一个类,类似如下:

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 的查询中,异常的堆栈跟踪也说明了这一点。但这只是第一次调用未初始化对象的成员(它仍然是 nullptr)。

因此,给有同样问题的其他用户的建议:向后检查堆栈以找到对 nullptr/null 对象的函数调用。

我现在的问题是:
为什么在第一次调用 oTest 的 nullptr 函数时执行不会失败?
为什么在第一次访问成员之前输入并执行函数?

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

【问题讨论】:

  • 那是如何引用 c# 的?
  • 我确信我可以轻松地在 C# 中编写类似的代码并导致相同的奇怪行为。因此,使用 c# 的用户可能会遇到同样的问题,我在这里给出一个解决方案。此外,我认为问题与 IL 或 JIT 编译器有关,因此也与 .net 有关。
  • 非静态类方法隐藏了用于访问类成员的“this”参数。因此,当使用空引用调用此类方法时,尝试访问类成员可能会失败。但一般来说,这是未定义的行为,它可能会在调用线上崩溃。
  • @AlexFarber:感谢您的解释。你可以自己回答。

标签: c++-cli nullreferenceexception


【解决方案1】:

这段代码:

 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。

【讨论】:

  • 我知道m_bInit 等于this->m_bInit。但我不知道编译器的其他细节。谢谢! (顺便说一句:我将删除 C# 标签,因为我现在看到它与 C# 无关)。
猜你喜欢
  • 1970-01-01
  • 2011-04-28
  • 1970-01-01
  • 1970-01-01
  • 2016-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-21
相关资源
最近更新 更多