包装非托管 C++使用 C++/CLI 的类库 - 问题 2 - 集合
注意:这篇文章代表了我的询问的问题#2。两个问题中都会重复介绍部分(达到数字之前的所有文本),因为它是回答问题可能需要的背景信息。
问题简介
我有一个非托管 C++ 库,其中包含多个“高级”库所共有和共享的类和函数。我现在需要向 C#/.Net 应用程序提供对公共库的访问。为此,我必须使用 C++/CLI 包装类来包装公共库。
公共库中包含的类可以是包含嵌套类定义和作为其他类对象集合的成员变量的复杂类。集合变量是用于管理集合的自定义列表类的 typedef 的实例。公共库还包括表示使用 FLEX/BISON 创建的自定义脚本文件语法的解析结构的类。公共库和“更高级别”库都是以允许跨平台(Linux 和 GCC)编译和使用的方式编写的。我所做的任何改变都必须考虑到这一点。
C++/CLI 包装类最初只需要读取功能。但随着项目的进展,我最终还需要能够创建和修改对象。
我了解 C++/CLI,并为其他非托管 C/C++ 项目创建了多个包装器,并为同一个公共库提供了抽象功能。所以我已经有了基础知识(和一些高级知识)。
我有两个与执行此任务相关的问题,因为它们都可以产生自己的讨论和解决方案,所以我将我的问题分成单独的帖子。我将在每篇文章中包含其他问题的链接。
实际问题
如何有效地包装/处理集合变量非托管类?
集合对象是自定义模板列表类 (
CObjectList
) 的 typedef,编写用于处理对象指针集合的管理。集合类提供所有基本集合功能以及指针管理和解构时对象的清理/释放。因此,对于CWidget
来说,将会有一个typedef CObjectList
在代码中。。 CWidgetList; 代码和集合类模板参数中使用的大多数类都是类本身。但在某些情况下,集合是基类的。这发生在自定义脚本 FLEX/BISON 解析器的解析结构中。例如,有一个 CCommand 类,所有其他可用命令都继承自该类。所以会有
CSetCommand
、CPrintCommand
、CIfCommand
等。我认为为了做到这一点,我必须创建我的集合包装类,该类为非托管类和 C++/CLI 类维护单独的列表。内部集合对象将管理非托管对象,并且必须有一个托管集合/列表对象来存储该项目的包装类。
有没有人提供如何执行此操作的示例/建议?或者如何编写一个可以同时采用非托管和 C++/CLI 类类型作为参数的泛型类?
Note: This post represents Question #2 of my inquiry. The introduction block (all text until the numbers are reached) is repeated in both questions as it is background information that may be needed to answer the question.
Introduction to Question
I have an unmanaged C++ library that contains classes and functions that are common to and shared among several "higher level" libraries. I now have need to provide access to the common library to C#/.Net applications. To do this, I will have to wrap the common library with C++/CLI wrapper classes.
The classes contained in the common library can be complex classes containing nested class definitions and member variables that are collections of other class objects. The collection variables are instances of typedefs of a custom list class for managing the collection. The common library also includes classes that represent the parsed structure of a custom script file syntax created using FLEX/BISON. The common library and the "higher level" libraries are all written in a fashion that allows for cross platform (Linux and GCC) compiling and usage. Any changes I make must still allow for this.
The C++/CLI wrapper classes at first need only read capability. But as the project advances, I'll eventually need to be able to create and modify the objects as well.
I know C++/CLI and have created several wrappers for other unmanaged C/C++ projects as well as providing abstracted functionality to this same common library. So I have the basics (and some advanced knowledge) already.
I have two questions related to performing this task and since they could both spawn their own discussions and solutions, I'm splitting my questions into separate posts. I'll include the link to the other question in each post.
Actual Questions
Wrapping an Unmanaged C++ Class Library with C++/CLI - Question 1 - Project/Code Organization
How do I efficiently wrap/handle collection variables in the unmanaged classes?
The collection objects are typedefs of a custom template list class (
CObjectList<T>
) written to handle management of a collection of object pointers. The collection class provides all the basic collection functionality as well as pointer management and cleanup/freeing of the objects on deconstruction. So forCWidget
there would be atypedef CObjectList<CWidget> CWidgetList;
in the code.Most of the classes used in the code and collection class template parameter are the class itself. But in some cases the collection is of a base class. This occurs in the parsed structure for the custom script FLEX/BISON parser. For example, there is a
CCommand
class that all the other available commands inherit from. So there would beCSetCommand
,CPrintCommand
,CIfCommand
, etc.I figure in order to do this, I'll have to create my collection wrapper class that maintains separate lists for unmanaged and C++/CLI classes. The inner collection object will manage the unmanaged object, and there'll have to be a managed collection/list object to store the wrapper class for the item.
Is there anyone that any examples/suggestions of how to do this? Or how to write a generic class that can take both unmanaged and C++/CLI class types as parameters?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是一个很难回答的问题,但我建议您有一个编组/转换层,可以将托管集合转换为非托管集合。让你的库保持原样,只需转换参数并返回即可。
这就是我会做的,
由于这些原因,
这将是我的默认方法,除非我真的需要访问数据结构中库的功能(这不仅仅是有组织的数据——但数据和行为)
This is a very hard question to answer, but I am going to suggest that you have a marshalling/conversion layer that converts from managed collections to unmanaged ones. Keep your library exactly as it is, and just convert the parameters and returns.
This is what I would do if
For these reasons
This would be my default approach unless I really needed access to the functionality of the lib in the datastructure (it wasn't just organized data -- but data and behavior)
Lou 拥有出色的建议,我同意他关于这种方法何时合适的条件。
相反,如果集合非常大,或者频繁地来回传递,则最好实现 .NET 可枚举接口,但不要使用 .NET 集合。基本上,您将拥有一个拥有本机 STL 集合的集合包装器和一个拥有本机 STL 迭代器的迭代器包装器。集合包装器将实现 IEnumerable 接口,而 GetEnumerator 将创建迭代器包装器的实例,迭代器包装器将实现 IEnumerator 接口。
您希望自己成为一个辅助托管类(可能是一个值类),它将指针包装到本机集合并进行引用计数,例如
boost::shared_ptr
。使用堆栈语义符号确保在托管集合包装器或迭代器包装器被处置时自动完成引用计数。Lou has an excellent suggestion and I agree with his conditions on when that approach is good.
If instead the collections are very large, or are passed back and forth frequently, you'd be better off implementing the .NET enumerable interface but not using .NET collections. Basically, you'd have a collection wrapper that owns a native STL collection, and an iterator wrapper that owns a native STL iterator. The collection wrapper would implement the
IEnumerable
interface andGetEnumerator
would create an instance of the iterator wrapper, the iterator wrapper would implement theIEnumerator
interface.You'd want to make yourself a helper managed class (probably a value class) that wraps the pointer to the native collection and does reference counting, like
boost::shared_ptr
. Use stack semantics notation to make sure that the reference counting gets done automatically when the managed collection wrapper or iterator wrapper get disposed.