因此,我有一个带有静态链接的MSVCRT副本的C++库。我希望任何人都能使用我的库与任何版本的MSVC运行时。实现这一目标的最佳方法是什么?
我已经对事情的处理方法非常小心了。
然而,我仍然有一些导致堆损坏的简单代码。
我的图书馆里有一个这样的东西:
class Foos
{
public: //There is an Add method, but it's not used, so not relevant here
DLL_API Foos();
DLL_API ~Foos();
private:
std::map<std::wstring, Foo*> map;
};
Foos::~Foos()
{
// start at the begining and go to the end deleting the data object
for(std::map<std::wstring, Foo*>::iterator it = map.begin(); it != map.end(); it++)
{
delete it->second;
}
map.clear();
}然后我从应用程序中使用它,如下所示:
void bar() {
Foos list;
}在我从任何地方调用这个函数之后,我会得到一个关于堆栈损坏的调试警告。如果我真的让它耗尽,它实际上破坏了堆栈和分段错误。
我的调用应用程序是用Visual 2012平台工具编译的。该库是使用Visual 2010平台工具编译的。
这只是我绝对不应该做的事情,还是我实际上违反了使用多个运行时的规则?
发布于 2013-11-14 16:44:54
内存永远不会通过DLL屏障。
但是,确实如此。很多次了。您的应用程序为类对象创建了存储,在本例中是在堆栈上。然后传递指向库中方法的指针。从构造函数调用开始。这个指针在库代码中。
在这种情况下,问题在于它没有创建正确的存储量。您可以让VS2012编译器查看类声明。它使用std::map的VS2012实现。但是,您的库是用VS2010编译的,它使用了完全不同的std::map的实现。有着完全不同的尺寸。多亏了C++11,发生了巨大的变化。
这只是完全的内存损坏,在您的应用程序中写入堆栈变量的代码将破坏std::map。相反的情况下。
跨模块边界公开C++类充满了类似的陷阱。只有当您能够保证所有的编译都使用完全相同的编译器版本和完全相同的设置时,才会考虑它。没有快捷方式,您也不能混合调试和发布构建代码。创建库以避免公开实现细节当然是可能的,您必须遵守以下规则:
到那时,您就可以很好地编写COM代码了,还可以使用您在例如DirectX中看到的样式。
发布于 2013-11-14 15:59:01
map成员变量仍然是由应用程序创建的,内部数据由应用程序分配,而不是DLL (它们可能使用不同的map实现)。根据经验,不要使用DLL中的堆栈对象,在DLL中添加类似于Foos * CreateFoos()的内容。
发布于 2013-11-14 16:13:43
运行时C++对象不会跨越障碍(例如,向量、映射等)。除非他们是在屏障的那边被创造出来的)
你就是这么做的。您的Foos对象由堆栈上的主程序创建,然后在库中使用。这个物体包含一个地图作为它的一部分..。
在编译主程序时,它会查看头文件等,以确定要为Foos对象分配多少堆栈空间。调用库中定义的构造函数..。可能期望对象的布局/大小完全不同。
https://stackoverflow.com/questions/19981921
复制相似问题