如何防止相同的非托管指针被封装在两个不同的 SafeHandles 中?

Posted

技术标签:

【中文标题】如何防止相同的非托管指针被封装在两个不同的 SafeHandles 中?【英文标题】:How can I prevent the same unmanaged pointer from being encapsulated in two different SafeHandles? 【发布时间】:2018-01-23 00:55:08 【问题描述】:

我正在为一个用 C 语言编写的游戏引擎编写一个托管包装器来挑战自己。我已经开始将非托管指针包装在SafeHandle 派生类中,但我认为调用可能返回相同指针的非托管函数可能会创建新的 SafeHandles,如果其中一个被释放,其余的将变为无效。

我怎样才能有效地防止这种情况发生?我怀疑编组器会自动跟踪重复项...

【问题讨论】:

你将如何在非托管代码中解决这个问题?在我看来,如果图书馆按照您的要求行事,那么它将无法使用。我宁愿怀疑您正在创建一个不存在的问题。 我不确定你的意思。在 C 程序中传递指针是正常的,不是吗?我只是想确保我检索到的每个指针都与一个 SafeHandle 类相关联,因此我不会实例化所有指向同一个非托管内存的唯一 SafeHandle 实例。 【参考方案1】:

您正在尝试解决大多数托管指针和非垃圾收集技术试图解决的问题。根据用例,有多种解决方案 -

    您可以使用引用计数 - 您基本上维护持有特定指针和重载(在 C 中使用函数调用而不是赋值)运算符的句柄数来更新赋值计数。然后,只有在计数达到0 后才释放指针。这种方法虽然准确,但开销很大,而且容易受到循环的影响,因此可能会泄漏内存。这是一个引用计数所有权模型。

    您可以创建一个unique_ptr。这基本上意味着在任何时候只有 1 个句柄持有对特定指针的引用。这意味着如果你做类似的事情 -

    a = b 
    

    指针将从b 复制到ab 将自动失效(更多的是API 的合同,而不是实现)。这意味着用户必须围绕这些约束构建代码。当任何持有引用的对象超出范围时,这里就完成了释放。这是一种独占所有权模式。

还有其他方法(例如weak_ptr),您可以在任何 C++ 参考资料中了解它们。

【讨论】:

我正在尝试处理托管 (C#) 方面的事情。这些听起来就像您在非托管 (C/C++) 端所做的。当我在 C# 中使用 P/Invoke 编组对 C 函数的调用时,我将 IntPtrs 编组为 SafeHandles,这意味着 marhsaller 将指针包装在一个对象中,因为它会自动返回。我要做的是减少 marhsaller 创建的 duplicate SafeHandle 对象的数量。【参考方案2】:

虽然这个答案是针对another question,但在这种情况下它会起作用。

我可以为我创建一个调用托管函数的工厂类,然后像 marhsaller 一样在 Constrained Execution Region 中手动创建 SafeHandles。这个工厂类可以跟踪非托管指针,如果已经创建了 SafeHandle,则返回它而不是创建新指针。

【讨论】:

致对我投反对票的人:这个答案有什么问题?

以上是关于如何防止相同的非托管指针被封装在两个不同的 SafeHandles 中?的主要内容,如果未能解决你的问题,请参考以下文章

几个appdomains调用相同的非托管DLL

实用的非基于图像的验证码方法?

如何在非托管 C++ 中捕获托管异常(来自委托)?

Vue JS 2. 如何防止在两个父级之间导航时重新加载相同的嵌套组件?

创建 2 个具有相同键列但不同包含列的非聚集索引

为啥指针+1包含的内存地址与被指向的值的地址+1不同