发布模式VS MS Visual Studio Windows中的DEbug模式

我正在使用MSVS 9(VS 2008)。 我的应用程序以及共享库(dll)(我用来链接我的应用程序)也是c ++环境。 现在观察下面的情况:

  1. 当共享库/ DLLbuild立在debugging模式,我的应用程序也build立在debugging模式结果:应用程序执行成功

  2. 当共享库/ DLLbuild立在发布模式,我的应用程序也build立在发布模式结果:应用程序执行成功

  3. 当共享库/ DLLbuild立在发布模式,我的应用程序也build立在debugging模式结果:应用程序正在崩溃,没有从调用堆栈中加载任何符号。

    调用堆栈:

    ntdll.dll中!76e94684()
    [下面的框架可能不正确和/或丢失,没有为ntdll.dll加载符号]

    ntdll.dll中!76e7d55f()
    ntdll.dll中!76e5fa18()
    ntdll.dll中!76e2b3c8()

当我尝试在我的应用程序中使用以下SetName()和GetName()定义时,会看到此问题。

using namespace std; void main() { Schema * schemaExp = new Schema(); schemaExp -> SetName("ExpSchema"); string srctable; srctable=schemaExp->GetName(); cout <<"\nConnection EXPORT using the target table:" << srctable.c_str() << endl; delete schemaExp; } 

模式类定义:

  using namespace std; class Schema { public: TELAPI_EXPORT void SetName(char *name); TELAPI_EXPORT string GetName(); protected: string tableName; }; void Schema::SetName(char *name) { string str(name); tableName = str; } string Schema::GetName() { return tableName; } 

注意:上面这个只是我应用程序的一部分,我的应用程序只在#3中崩溃,并且在上面的#1和#2情况下正常工作

请帮我解决这个问题。 任何forms的帮助,非常感谢。

提前致谢。

Solutions Collecting From Web of "发布模式VS MS Visual Studio Windows中的DEbug模式"

当共享库/ DLL建立在发布模式,我的应用程序也建立在调试模式结果:应用程序正在崩溃,没有从调用堆栈中加载任何符号。

这是因为这不是受支持的配置。 默认情况下,调试和发布目标链接到不同版本的CRT,(除其他外)使用不同的策略来分配内存,并且彼此不兼容。

这只是更一般的规则的扩展,你不应该混合链接到不同版本CRT的库。 所有的项目都需要匹配。 正如你已经看到的,当他们做的时候,一切正常。

对此有一些解决方法,但是他们需要做很多工作才能获得正确的结果。 从本质上讲,你要确保所有的内存分配在单个DLL中是隔离的,这样没有任何东西跨越模块边界。 您需要从DLL中导出特定的函数来分配和释放内存,以确保分配内存的堆管理器与销毁内存的堆管理器是相同的。 当你使用newdelete操作符时,你不能依赖这种情况。 坦率地说,在这种情况下,我不明白这些努力如何为您带来什么有用的东西。

请注意,这与是否启用优化无关(默认情况下,它们是Release版本,不在Debug版本中)。 该设置与所链接的CRT版本正交。“调试”和“释放”目标意味着多个选项。 您可以打开一个项目的优化,并关闭另一个,这应该工作,只要你确保他们都链接到同一版本的CRT。 但是,我再也看不到这一点,如果你想为其中一个优化启用,你为什么要把它们压缩为另一个呢?

相关: 混合调试和发布库/二进制文件 – 不好的做法?

这不应该是一个崩溃,但是,通常你会在Windows内存管理器中得到一个调试中断来警告你,你的程序正在销毁这个堆。 Windows中调试堆的功能,在Vista和更高版本上可用。 在输出窗口中查看消息。

启用符号服务器也很重要,以便堆栈跟踪变得可读和准确。 使用工具+选项,调试,符号,然后勾选预定义的msdl.microsoft.com服务器名称前面的复选框。 为符号存储选择一个好的暂存目录。 当你再次启动你的程序时,它会运行一段时间,然后开始运行,下载符号文件。 这只发生一次。 你现在应该得到一个高度可读的堆栈跟踪,现在也可以回到你的main()方法。

一般来说,发现在模块边界上暴露C ++类是棘手的事情。 不止一件事情可能会出错,这里的一个失败模式是模式类对象在DLL边界两侧的大小不一样。 这是因为Debug版本设置, _HAS_ITERATOR_DEBUGGING#定义很重要。 它在Debug版本中默认打开,在Release版本中关闭。 很好的调试功能,但是他们可以实现的唯一方法是向标准C ++库类添加字段。 这使得Debug版本中的std :: string更大。 这使得你的Scheme类更大。 您现在正在避开这个问题,失败模式是EXE版本的DLL的Debug版本。 当初始化字符串时,Scheme类的构造函数会损坏堆,因为对象的分配不够大。

另一种失败模式是,在进程中有两个版本的CRT,在你的应用程序中有调试版本,在你的DLL中有版本版本。 他们不会使用相同的堆来分配。 当你分配一个而另一个释放的时候会出错。 GetName()方法返回的字符串遇到这个问题,它是在DLL中的GetName()方法中创建的,并且会在EXE中的方法调用之后被销毁。 由错误的分配器。 直到您再次对堆执行操作(例如删除您的Scheme对象),才会检测到堆所造成的损坏。 如果不使用/ MD编译您的代码,您也会调用这个失败模式。 这个问题在VS2012中得到了解决,所有的分配现在都是由默认的进程堆进行的。

使用一致的构建设置对于存活模块边界至关重要。 设置你的VS解决方案,以便始终如一地使用正确的DLL构建不是问题,只要确保DLL项目与EXE项目在同一个解决方案。

但是请注意,将来你可能会遇到麻烦,一个DLL有一个自己的生活诀窍,有一天可能会被另一个版本的编译器构建的应用程序使用。 那么Kaboom。 设计你的DLL接口,这是不可能发生的,但是你将不得不放弃暴露C ++对象。 一个C风格的接口是后备,COM的工作方式提升到一个对象模型也是一个很好的方法。 这当然是非常严厉的,只有在不能保证EXE和DLL总是同时被构建和部署的情况下才考虑这一点。