C++ :我什么时候需要 std::vector 的共享内存分配器?

发布于 2024-08-13 05:03:38 字数 1461 浏览 3 评论 0原文

First_Layer

我有一个用 VC++6 service pack 6 编写的 win32 dll。我们将此 dll 称为 FirstLayer。我无权访问 FirstLayer 的源代码,但我需要从托管代码中调用它。问题是 FirstLayer 大量使用 std::vector 和 std::string 作为函数参数,并且无法直接将这些类型封送到 C# 应用程序中。

Second_Layer

我能想到的解决方案是首先创建另一个用VC++6 service pack 6编写的win32 dll。我们将这个dll称为“SecondLayer”。 SecondLayer 充当 FirstLayer 的包装器。该层包含 std::vector 的包装类,因此 std::vector 不会在此层的所有函数参数中公开。我们将 std::vector 的包装类称为 StdVectorWrapper。

该层不使用任何新的或删除操作来分配或释放内存,因为这是由 std::vector 内部处理的。

Third_Layer

我还创建了一个 VC++2005 类库作为 SecondLayer 的包装器。这个包装器完成了将非托管 SecondLayer 转换为托管代码的所有脏工作。我们将此层称为“第三层”。

与SecondLayer类似,该层在处理StdVectorWrapper时不使用new和delete。

Fourth_Layer

最重要的是,我创建了一个 C#2005 控制台应用程序来调用 ThirdLayer。我们将此 C# 控制台应用程序称为“FourthLayer”。

调用序列摘要

FourthLayer(C#2005) ->第三层(VC++2005)->第二层(VC++6) -> FirstLayer(VC++6)

问题

我注意到“System.AccessViolationException:尝试读取或写入受保护的内存”异常被抛出,我怀疑这是由于SecondLayer 的内部 std::vector 分配内存,这对于 ThirdLayer 访问是非法的。

我认为这是证实的,因为当我在 VC++2005 中重新编译 FirstLayer(模拟)和 SecondLayer 时,问题完全消失。但是,由于我没有源代码,因此无法重新编译 FirstLayer 的生产版本。

我听说为了摆脱这个问题,我需要用 C++ 为 SecondLayer 的 std::vector 编写一个共享内存分配器,该分配器位于 StdVectorWrapper 类中。我不完全理解为什么需要共享内存分配器以及它是如何工作的?有什么想法吗?

互联网上是否有任何可用的源代码,我可以将其与 SecondLayer 中的代码一起编译和使用?

请注意,我无法为此使用 boost 库。

First_Layer

I have a win32 dll written in VC++6 service pack 6. Let's call this dll as FirstLayer. I do not have access to FirstLayer's source code but I need to call it from managed code. The problem is that FirstLayer makes heavy use of std::vector and std::string as function arguments and there is no way of marshaling these types into a C# application directly.

Second_Layer

The solution that I can think of is to first create another win32 dll written in VC++6 service pack 6. Let's call this dll as "SecondLayer". SecondLayer acts as a wrapper for FirstLayer. This layer contains wrapper classes for std::vector so std::vector is not exposed in all function parameters in this layer. Let's call this wrapper class for std::vector as StdVectorWrapper.

This layer does not make use of any new or delete operations to allocate or deallocate memory since this is handled by std::vector internally.

Third_Layer

I also created a VC++2005 class library as a wrapper for SecondLayer. This wrapper does all the dirty work of converting the unmanaged SecondLayer into managed code. Let's call this layer as "ThirdLayer".

Similar to SecondLayer, this layer does not make use of new and delete when dealing with StdVectorWrapper.

Fourth_Layer

To top it all, I created a C#2005 console application to call ThirdLayer. Let's call this C# console application as "FourthLayer".

Call Sequence Summary

FourthLayer(C#2005) -> ThirdLayer(VC++2005) -> SecondLayer(VC++6) -> FirstLayer(VC++6)

The Problem

I noticed that the "System.AccessViolationException: Attempted to read or write protected memory" exception is being thrown which I suspect to be due to SecondLayer's internal std::vector allocating memory which is illegal for ThirdLayer to access.

This is confirmed I think because when I recompile FirstLayer (simulated) and SecondLayer in VC++2005, the problem disappears completely. However, recompiling the production version of FirstLayer is not possible as I do not have the source code.

I have heard that in order to get rid of this problem, I need to write a shared memory allocator in C++ for SecondLayer's std::vector which is found in the StdVectorWrapper class. I do not fully understand why I need a shared memory allocator and how it works? Any idea?

Is there any readily available source code for this on the internet that I can just compile and use together with my code in SecondLayer?

Note that I am unable to use the boost library for this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

沙与沫 2024-08-20 05:03:38

每个可执行文件或 dll 都链接到特定版本的 c 运行时库,其中包含 new 和 delete 的实现。如果两个模块具有不同的编译器(VC2005 与 VC6)或构建设置(调试与发布)或其他设置(多线程运行时与非多线程运行时),那么它们将链接到不同的 c 运行时。如果一个运行时分配的内存被另一个运行时释放,这就会成为一个问题。

现在,如果我没有记错的话,模板(例如 std::vector 或 std::string)可能会导致这个问题潜入不明显的地方。问题来自于模板被单独编译到每个模块中的事实。

示例:模块 1 使用向量(从而分配内存),然后将其作为函数参数传递给模块 2,然后模块 2 操作向量导致内存被释放。在本例中,内存是使用模块 1 的运行时分配的,并使用模块 2 的运行时释放的。如果这些运行时不同,那么就有问题了。

因此,考虑到所有这些,您有两个地方可能会出现潜在问题。一个是 FirstLayer 和 SecondLayer 之间,如果这两个模块没有使用完全相同相同的设置进行编译。如果在一个层中分配了任何内存并在另一个层中释放了内存,则另一个位于 SecondLayer 和 ThirdLayer 之间。

您可以再编写几个测试程序来确认哪些地方有问题。

要测试 FirstLayer-SecondLayer,请将 SecondLayer 函数的实现复制到 VC6 程序中,编写足够的代码以典型方式调用这些函数,并仅链接到 FirstLayer。

如果第一个测试没有失败,或者一旦您修复了它,则测试 SecondLayer-ThirdLayer:将 ThirdLayer 实现复制到 VC2005 程序中,编写代码以进行典型调用,然后链接到 SecondLayer。

Each executable or dll links to a particular version of the c runtime library, which is what contains the implementation of new and delete. If two modules have different compilers (VC2005 vs VC6) or build settings (Debug vs Release) or other settings (Multithreaded runtime vs non-multithreaded runtime), then they will link to different c runtimes. That becomes a problem if memory allocated by one runtime is freed by a different runtime.

Now, if I'm not mistaken, templates (such as std::vector or std::string) can cause this problem to sneak in where it isn't immediately obvious. The issue comes from the fact that templates are compiled into each module separately.

Example: module 1 uses a vector (thus allocating memory), then passes it as a function parameter to module 2, and then module 2 manipulates the vector causing the memory to be deallocated. In this case, the memory was allocated using module 1's runtime and deallocated using module 2's runtime. If those runtimes are different, then you have a problem.

So given all that, you have two places for potential problems. One is between FirstLayer and SecondLayer if those two modules haven't been compiled with the exact same settings. The other is between SecondLayer and ThirdLayer if any memory is allocated in one and deallocated in the other.

You could write a couple more test programs to confirm which place(s) have problems.

To test FirstLayer-SecondLayer, copy the implementation of the SecondLayer functions into a VC6 program, write just enough code to call those functions in a typical manner, and link only against FirstLayer.

If that first test doesn't fail, or else once you've fixed it, then test SecondLayer-ThirdLayer: copy the ThirdLayer implementation into a VC2005 program, write the code to make typical calls, and link against SecondLayer.

悍妇囚夫 2024-08-20 05:03:38

我认为您应该考虑不同的解决方案架构。

我相信,VC6 stl 向量和字符串生成的二进制代码与较新版本的 VC 生成的代码不同,因为有许多 stl 升级。因此,我认为您的体系结构无法正常工作,因为 dll 将具有两种不二进制兼容的 std::vector 和 std::string 实现。

我建议的解决方案是返回到 VC6 并为 FirstLayer 编写一个新的包装器 dll,通过纯 C API 公开它——该层需要使用 VC6sp6 进行编译,以确保它与 FirstLayer 二进制兼容。然后使用 Fourth_Layer 中的 PInvoke 来访问 VC6 包装器 DLL。

I think you should look at a different solution architecture.

The binary code generated by VC6 stl vector and string is, I believe, different from the code generated by more recent version of VC because of the many stl upgrades. Because of this I don't think your architecture will work as the dlls will have two implementations of std::vector and std::string that are not binary compatible.

My suggested solution is to go back to VC6 and write a new wrapper dll for FirstLayer that exposes it via a pure C API -- this layer will need to be compiled using VC6sp6 to ensure it is binary compatible with FirstLayer. Then use PInvoke in Fourth_Layer to access the VC6 wrapper DLL.

—━☆沉默づ 2024-08-20 05:03:38

我已经找到了问题的解决方案。基本上,我编写的 StdVectorWrapper 类没有实现深度复制。所以我需要做的就是将以下内容添加到 StdVectorWrapper 类中以实现深度复制。

  • 复制构造函数
  • 赋值运算符
  • 解构函数

编辑:替代解决方案

更好的解决方案是使用 clone_ptr 用于 std::vector 中包含的所有元素以及 std::vector 本身。这消除了对复制构造函数、赋值运算符和解构函数的需要。

I have found a solution for the problem. Basically, the StdVectorWrapper class which I wrote do not implement deep copy. So all I need to do is to add the following to the StdVectorWrapper class to implement deep copy.

  • Copy Constructor
  • Assignment Operator
  • Deconstructor

Edit: Alternative Solution

An even better solution would be to use clone_ptr for all the elements contained in std::vector as well as for std::vector itself. This eliminates the need for the copy constructor, assignment operator and deconstructor.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文