Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrapping an Unmanaged C++ Class Library with C++/CLI - Question 2 - Collections

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

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

  2. 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 for CWidget there would be a typedef 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 be CSetCommand, 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?

like image 664
CuppM Avatar asked Jan 27 '11 17:01

CuppM


2 Answers

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

  1. The collections aren't giant
  2. They aren't constantly passed back and forth all of the time.
  3. You often get the collection in the client code and then do a bunch of calls on it completely in managed land.

For these reasons

  1. It layers the API keeping it simpler
  2. crossing the unmanaged/managed boundary can be a bottleneck and should be minimized

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)

like image 76
Lou Franco Avatar answered Nov 14 '22 23:11

Lou Franco


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 and GetEnumerator would create an instance of the iterator wrapper, the iterator wrapper would implement the IEnumerator 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.

like image 44
Ben Voigt Avatar answered Nov 15 '22 01:11

Ben Voigt