【问题标题】:Destructor crash析构函数崩溃
【发布时间】:2010-11-05 18:30:40
【问题描述】:

我正在 Visual Studio 中开发 Win32 c++ 应用程序。

在其中一个源文件中,我有如下全局对象。

TestClass tObj;

int main() //Execution starts here
{
}

TestClass 在其他 DLL 中定义,如下所示。

struct Source
{

};

class TestClass
{
  list<Source> sourceList;
    public:
         TestClass() {}
        ~TestClass() {}
};

当我的应用程序正在运行时,如果我尝试明确关闭应用程序, 通过关闭控制台窗口,它在 TestClass 析构函数中崩溃。 Callstack 显示 CrtIsValidHeapPointer 失败。

请帮我解决这个问题。

【问题讨论】:

  • 使用四个空格缩进代码,不使用普通文本。
  • 您是否使用相同的 C++ 运行时构建了 exe 和 DLL?
  • 是的,我都使用 Visual Studio 构建。只有配置类型不同。一个是exe,一个是项目设置中的DLL配置。
  • 如何将 dll 链接到 exe ?通过传统的静态链接(使用 .lib)
  • 崩溃是通过在 exe 和 dll 中使用相同的运行时库来解决的。谢谢大家帮助我。

标签: c++ destructor


【解决方案1】:

您的问题是 .exe 和 .dll 之间不同的编译器/链接器设置实际上导致 .dll 和 .exe 使用标准库的不同实现:

  • 您必须使用相同的预处理器标志* 来构建 .exe 和 .dll,否则每个二进制文件都将使用略有不同的实现进行编译。
  • 您必须将 .exe 和 .dll 都链接到动态运行时。静态链接到运行时的二进制文件拥有自己的堆 - 您最终会在一个堆上分配并尝试在另一个堆上释放。

要解决此问题,请转到 Project &gt; Properties &gt; Configuration Properties &gt; C/C++ &gt; Code Generation 并将运行时库选项更改为 Multi-threaded Debug DLL (/MDd)。您必须对 .exe 项目和 .dll 项目都执行此操作。

从 Visual Studio 2010 开始,部分此类错误将在链接时使用 #pragma detect_mismatch 检测到。

*对于所有对标准库实现有任何影响的预处理器标志

【讨论】:

  • +1 从我这里得到这个全面的答案。 @bjskishore123:请阅读FAQ。我们鼓励您接受您认为最能帮助您解决问题的答案。
【解决方案2】:

确保使用相同的运行时构建机器人 EXE 和 DLL,最好使用动态运行时。

【讨论】:

  • 崩溃是通过在 exe 和 dll 中使用相同的运行时库来解决的。谢谢大家帮助我。
【解决方案3】:

它在析构函数中崩溃,正在从调用终止的析构函数中抛出异常并导致应用程序崩溃。Uncaught exceptions

有两种情况会调用析构函数。第一种是当对象在“正常”条件下被销毁时,例如,当它超出范围或被显式删除时。第二种是对象在异常传播的堆栈展开部分被异常处理机制破坏。您必须在异常处于活动状态这一保守假设下编写析构函数,因为如果控制因异常而离开析构函数而另一个异常处于活动状态,C++ 将调用终止函数

【讨论】:

  • 全局对象在 main() 被调用之前被构建。所以我认为,它的破坏发生在 main() 退出之后。那个时候,STL内部使用的list sourceList head,在释放的时候是无效的。因此 CrtIsValidHeapPointer 失败了。
  • 问题是:为什么sourceList头部无效?如果您的 exe 和 DLL 是使用兼容的运行时正确构建的,那么此代码应该可以正常工作。运行时将在释放堆之前清理全局对象。
  • 崩溃是通过在 exe 和 dll 中使用相同的运行时库来解决的。谢谢大家帮助我。
【解决方案4】:

全局对象由 C 运行时初始化和销毁​​。它们在main 被调用之前被初始化并在它返回后被销毁。

该错误可能是由您的 TestClass 析构函数(或间接从 Source 析构函数)访问的某些内容引起的。析构代码正在访问无效内存(或已被释放的内存)。

全局变量的初始化和销毁​​顺序没有定义,并且经常是应用程序终止时的错误来源。如果有其他全局变量可能会清理或修改 TestClass 引用的资源,那么这可能是罪魁祸首。

【讨论】:

  • 我没有向 sourceList(list) 添加任何节点。调用析构函数时列表为空。但是,STL List 内部会有一个隐藏的 Head 指针。在尝试释放它时,它崩溃了。
  • 您针对哪些 CRT 构建 EXE 和 DLL?
【解决方案5】:

DLL 和 EXE 是否使用相同的对齐方式(pack pragma)构建?

【讨论】:

    【解决方案6】:

    尝试使您的构造函数和析构函数非内联,这可能会有所帮助。如果 ctor 和 dtor 不是内联的,则两者都会代表 dll 生成,因此 list 的构造和销毁将使用同一个运行时库执行。 通常,尽量避免跨 dll 边界传递不透明的 stl 对象。最好将它们作为私有成员封装到您自己的类中,并提供非内联方法来操作此类成员

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-28
      • 2012-09-29
      • 1970-01-01
      • 2023-03-15
      • 2013-04-13
      • 1970-01-01
      • 2013-03-14
      • 2014-12-15
      相关资源
      最近更新 更多