gpt4 book ai didi

c++ - 混合版本的 MSVCRT

转载 作者:可可西里 更新时间:2023-11-01 18:17:15 27 4
gpt4 key购买 nike

因此,我有一个 C++ 库,其中包含 MSVCRT 的静态链接拷贝。我希望任何人都能够将我的库与任何版本的 MSVC 运行时一起使用。实现这个目标的最佳方式是什么?

我已经非常注意事情的完成方式。

  1. 内存永远不会通过 DLL 屏障而被释放
  2. 运行时 C++ 对象不会跨越障碍(即 vector 、映射等,除非它们是在障碍的那一侧创建的)
  3. 没有文件句柄或资源句柄在屏障之间传递

然而,我仍然有一些导致堆损坏的简单代码。

我的库中有这样一个对象:

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 Studio 2012 平台工具编译的。该库是使用 Visual Studio 2010 平台工具编译的。

这是我绝对不应该做的事情,还是我实际上违反了使用多个运行时的规则?

最佳答案

Memory never passes the DLL barrier

但是,确实如此。事实上很多次。您的应用程序为类对象创建了存储,在本例中是在堆栈上。然后传递一个指向库中方法的指针。从构造函数调用开始。该指针是库代码中的this

在这种情况下,问题在于它没有创建正确的存储量。你让 VS2012 编译器查看你的类声明。它使用 std::map 的 VS2012 实现。然而你的库是用 VS2010 编译的,它使用了一个完全不同的 std::map 实现。尺寸完全不同。得益于 C++11 的巨大变化。

这只是工作中的完全内存损坏,您的应用程序中写入堆栈变量的代码将损坏 std::map。反之亦然。

跨模块边界公开 C++ 类充满了这样的陷阱。只有当您可以保证所有内容都是使用完全相同的编译器版本和完全相同的设置编译时才考虑它。没有捷径可走,您也不能混合调试和发布构建代码。编写库以公开实现细节当然是可能的,您必须遵守以下规则:

  • 仅使用虚方法公开纯接口(interface),参数类型必须是简单类型或接口(interface)指针。
  • 使用类工厂创建接口(interface)实例
  • 使用引用计数进行内存管理,因此总是由库进行释放。
  • 使用硬性规则确定核心细节,例如打包和调用约定。
  • 绝不允许异常跨越模块边界,只使用错误代码。

届时您将能够很好地编写 COM 代码,以及您在 DirectX 中看到的样式。

关于c++ - 混合版本的 MSVCRT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19981921/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com