MSVC 2010 编译应用程序和 MSVC 2019 编译应用程序之间的行为差异



我正在开发MFC应用程序。我们最近将应用程序从使用 MSVC 2010 编译器(v100 工具集(迁移到使用 MSVC 2019 编译器(v142 工具集(。升级到 MSVC 2019 后,我们看到应用程序的行为存在一个差异。

在使用 MSVC 2010 编译器(v100 工具集(编译的应用程序中,当应用程序的主窗口关闭时,应用程序通过调用主框架窗口类的 OnClose(( 函数启动退出过程。在销毁序列期间,我们在其中一个类的析构函数中具有日志记录代码,该代码实际上最终取消引用了一个悬空指针(此指针指向日志记录类的实例,导致访问冲突的行正在尝试调用此日志记录类实例上的函数,该函数之前已被销毁(。发生此访问冲突时,我可以在 Visual Studio 2010 输出窗口中看到消息"在 :0xC0000005:位置访问冲突中的首次机会异常"。我们在此特定调用层次结构中没有任何 catch 块来捕获此访问冲突异常,因此我们希望应用程序终止。按 F10 后(看看我是否可以移动到下一行(,此时显示的调用堆栈如下所示:

exe_name!"class_name::function_name'::'1'::catch$0(( 第 line_no 行

Msvcr100.dll!_CallSettingFrame(( 第 44 行

Msvcr100.dll!_CxxCallCatchBlock(_EXCEPTION_RECORD * pExexcept( 1337行

当我调试并按 F10 时,我能够继续通过导致访问冲突的行。看起来运行时正在抑制异常(或以某种方式捕获它(,因为我能够越过导致访问冲突的行。任何人都可以解释为什么即使在存在未处理的异常之后,应用程序仍在继续。

我们在 VC 10 和 VC 19 的 exe 项目属性中为"C/C++ -> 代码生成 ->启用C++异常"选择了编译器选项"是,SEH 异常 (/EHa("。

在使用 MSVC 2019 编译器(v142 工具集(编译的应用程序中,完全相同的代码行会导致运行时检测到纯虚函数调用,并且应用程序崩溃。我想了解的正是这种行为差异(MSVC 2010 编译应用程序和 MSVC 2019 编译应用程序之间(。

我确实知道取消引用悬空指针会导致未定义的行为。但是,我无法理解在VC 2010编译的应用程序中,我如何能够调试(或继续(通过导致访问冲突异常(尚未处理(的行。

欢迎来到未定义行为的奇怪世界,在这里任何事情都可能发生(好吧,也许什么都不是,但很多坏事都可能发生(。

我确实知道取消引用悬空指针会导致未定义的行为。但是,我无法理解在VC 2010编译的应用程序中,我如何能够调试(或继续(通过导致访问冲突异常(尚未处理(的行。

关键是它没有解释。或者更确切地说,它是未定义行为的事实本身就是解释。一旦程序中有未定义的行为,所有赌注都将关闭。它完全可以工作,然后继续前进。另一方面,它可能会崩溃。你现在永远不会真正得到哪一个。

这正是您不应该在程序中出现未定义行为的原因。你不能保证它适用于每个实现,甚至有时甚至相同的实现。有时编译器会选择以不同的方式优化内容,并导致您以前工作的代码崩溃。所以通常最好避免。

至于为什么在这种情况下这样做,Microsoft很可能已经改变了它们的实现,从而对您执行此操作而不会崩溃的能力产生了不利影响。但具体是什么,我无法告诉你。我不知道Microsoft在它们的实现中做了什么,以及你在代码中做什么的具体例子,我就没有真正的方法知道。

我的建议是,既然你似乎已经知道错误来自哪里,那就简单地找到一种方法来确保你在指针被破坏后不会尊重指针。这样,您可以确保无论您使用哪种编译器,它都可以工作。

最新更新