【问题标题】:Wrapping an Unmanaged C++ Class Library with C++/CLI - Question 2 - Collections使用 C++/CLI 包装非托管 C++ 类库 - 问题 2 - 集合
【发布时间】:2011-01-27 17:36:18
【问题描述】:

注意:这篇文章代表了我询问的问题 #2。在两个问题中重复介绍部分(直到达到数字为止的所有文本),因为它是回答问题可能需要的背景信息。


问题简介

我有一个非托管 C++ 库,其中包含几个“更高级别”库共有的类和函数。我现在需要为 C#/.Net 应用程序提供对公共库的访问权限。为此,我必须使用 C++/CLI 包装类来包装公共库。

公共库中包含的类可以是包含嵌套类定义和成员变量的复杂类,这些成员变量是其他类对象的集合。集合变量是用于管理集合的自定义列表类的 typedef 实例。公共库还包括表示使用 FLEX/BISON 创建的自定义脚本文件语法的解析结构的类。公共库和“更高级别”库都以允许跨平台(Linux 和 GCC)编译和使用的方式编写。我所做的任何更改都必须允许这样做。

C++/CLI 包装类最初只需要读取能力。但随着项目的推进,我最终也需要能够创建和修改对象。

我了解 C++/CLI,并为其他非托管 C/C++ 项目创建了多个包装器,并为同一个通用库提供了抽象功能。所以我已经掌握了基础知识(和一些高级知识)。

我有两个与执行此任务相关的问题,因为它们都可以产生自己的讨论和解决方案,所以我将我的问题分成不同的帖子。我将在每个帖子中包含指向另一个问题的链接。


实际问题

  1. Wrapping an Unmanaged C++ Class Library with C++/CLI - Question 1 - Project/Code Organization

  2. 如何有效地包装/处理非托管类中的集合变量?

    • 集合对象是自定义模板列表类 (CObjectList<T>) 的 typedef,用于处理对象指针集合的管理。集合类提供所有基本的集合功能以及指针管理和解构时对象的清理/释放。所以对于CWidget,代码中会有一个typedef CObjectList<CWidget> CWidgetList;

    • 代码和集合类模板参数中使用的大部分类都是类本身。但在某些情况下,该集合属于基类。这发生在自定义脚本 FLEX/BISON 解析器的解析结构中。例如,所有其他可用命令都继承自 CCommand 类。所以会有CSetCommandCPrintCommandCIfCommand等。

    • 我认为为了做到这一点,我必须创建我的集合包装类,该类为非托管类和 C++/CLI 类维护单独的列表。内部集合对象将管理非托管对象,并且必须有一个托管集合/列表对象来存储项目的包装类。

    • 有没有人可以提供有关如何执行此操作的示例/建议?或者如何编写一个可以同时接受非托管和 C++/CLI 类类型作为参数的泛型类?

【问题讨论】:

  • 你应该编辑你的original question(尤其是因为它没有答案)而不是重新发布。
  • 什么意思?数字项目是问题。前面的内容是正确回答问题可能需要知道的背景信息。他们都在 5 分钟内发布。
  • 您可能想让两个不同问题的标题“更加不同”。为了避免它显示为转发。
  • 啊。我明白你的意思了。我认为标题的名称更具层次性。

标签: .net visual-c++ collections c++-cli wrapper


【解决方案1】:

这是一个很难回答的问题,但我建议您有一个编组/转换层,可以将托管集合转换为非托管集合。保持库原样,只需转换参数和返回。

如果是这样,我会这样做

  1. 馆藏并不庞大
  2. 它们不会一直不断地来回传递。
  3. 您经常在客户端代码中获取集合,然后在托管区域中对其进行大量调用。

由于这些原因

  1. 它对 API 进行分层,使其更简单
  2. 跨越非托管/托管边界可能成为瓶颈,应尽量减少

这将是我的默认方法,除非我真的需要访问数据结构中 lib 的功能(它不仅仅是有组织的数据——而是数据和行为)

【讨论】:

  • 成员变量集合不是巨大的(在我习惯认为巨型的术语中),但对于某些东西,它们可能包含几百个项目。对于不是成员变量的其他集合,它们可能包含 50k+ 项。你有提供这方面信息的链接吗?在谷歌搜索信息时,我确实看到了该选项,但我看到的所有内容都只使用简单的结构/类,并且没有一个带有集合的示例。
  • 就您对库功能的访问而言,初始阶段是提供从库中读取的能力(例如表示已解析脚本文件的类)。下一阶段将允许用户创建/修改脚本对象并序列化回脚本文件。该库还包含一个类或从 SQLite 数据库的“更高级别”库中读取和写入输出。所以我也需要提供访问权限。
  • 这很棘手——我不认为你会发现任何值得写的东西。没有多少人讨论 C 库的复杂 C++/CLI 包装。 50k+ 项不应该听从我的建议。
【解决方案2】:

Lou has an excellent suggestion 并且我同意他关于何时采用这种方法的条件。

如果集合非常大,或者经常来回传递,则最好实现 .NET 可枚举接口但不使用 .NET 集合。基本上,您将拥有一个拥有本机 STL 集合的集合包装器和一个拥有本机 STL 迭代器的迭代器包装器。集合包装器将实现IEnumerable 接口,GetEnumerator 将创建迭代器包装器的实例,迭代器包装器将实现IEnumerator 接口。

你想让自己成为一个辅助托管类(可能是一个值类),它包装指向本机集合的指针并进行引用计数,例如boost::shared_ptr。使用堆栈语义符号确保在托管集合包装器或迭代器包装器被释放时自动完成引用计数。

【讨论】:

  • 是的,写一个实现IEnumerableIList等的包装类是我最初的设想。为什么 value class 会比普通的 ref class 更好地包装集合?引用计数是否针对为每个非托管列表项实例化的托管包装类的数量?
  • 我的意思是引用计数指针应该是一个值类。集合包装器当然可以是引用类。并且引用计数是只要 IEnumerator 包装器存在,即使 IEnumerable 集合包装器已被释放,本机集合也会保持活动状态。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多