|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionChoosing the right programming language for .NET is mostly a matter of personal preference and the problem that needs to be solved. For me, one of the most important reasons to use managed extensions for C++ (MC++) is the possibility to reuse "native" C++ code, especially C++ Standard Library. In the October 2002 edition of C/C++ User Journal, there is an article by Jonathan Caves, that describes some issues with using C++ Standard Library with managed types. My aim is to go one step further and offer some code that will help developers to easily integrate managed types and STL. This code is contained in a single header file gcstl.h. To use the code I provided here, you will need working knowledge of Managed Extensions for C++ and STL. That assumes that, at least you have read Managed Extensions for C++ Specification and some introductionary STL text. To really understand what is going on under the hood, you will need to be familiar with STL internals, and to have a good understanding of CLR and .NET Framework. What is the problem?To illustrate the problems with working with managed types and STL, try to compile the next piece of code: #using <mscorlib.dll> #include <vector> #include <algorithm> #include <iterator> #include <iostream> using namespace System; using namespace std; int main() { vector <String __gc*> v; //Problem 1 v.push_back(S"bca"); v.push_back(S"bac"); v.push_back(S"abc"); sort (v.begin(), v.end()); //Problem 2 copy (v.begin(), v.end(), ostream_iterator<String __gc*>(wcout, L" ")); //Problem 3 } Also, it would be nice if we could use STL algorithms with .NET collections. Something like: String __gc* st_array[] = {S"bca", S"bac", S"abc"}; std::find(st_array[0], st_array[3], S"abc"); //Problem 4 The code above has following problems:
Let's discuss each of those problems separately. Problem 1: Storing __gc Pointers in STL ContainersAs explained in Managed Extensions for C++ Specification, chapter 16.3 "It is illegal to declare a member of an unmanaged class to have #using <mscorlib.dll> #include <vector> #include <algorithm> #include <iterator> #include <iostream> #include <vcclr.h> using namespace System; using namespace std; int main() { //vector <String __gc*> v; //Problem 1 vector <gcroot<String __gc*> > v; v.push_back(S"bca"); v.push_back(S"bac"); v.push_back(S"abc"); /* sort (v.begin(), v.end()); //Problem 2 copy (v.begin(), v.end(), ostream_iterator<String __gc*>(wcout, S" ")); //Problem 3 */ } To find out about internals of Problem 2: Comparisons of Managed ObjectsTo work with STL algorithms, as well as with sorted containers, you must be able to compare the values of your objects. STL heavily relies on value semantics, and it is generally recommended to avoid pointers ( #using <mscorlib.dll> #include <vector> #include <algorithm> #include <iterator> #include <iostream> #include "gcstl.h" using namespace System; using namespace std; int main() { //vector <String __gc*> v; //Problem 1 vector <gcroot<String __gc*> > v; v.push_back(S"bca"); v.push_back(S"bac"); v.push_back(S"abc"); //sort (v.begin(), v.end()); //Problem 2 sort (v.begin(), v.end(), gc_less<String __gc*>()); /* copy (v.begin(), v.end(), ostream_iterator<String __gc*>(wcout, S" ")); //Problem 3 */ } Note that, we now use the version of sort, which uses a user-defined predicate function object that defines the comparison criterion. Most STL algorithms have versions that enable users to provide comparison predicates. In the header file gcstl.h, I define comparison function objects that work with set<gcroot<String __gc*>, gc_less<String __gc*>()> my_set; rather than: set<gcroot<String __gc*> > my_set; Actually, both versions will compile, but in the later case ordering will be meaningless. Function objects defined in gcstl.h are listed in the following table:
From the table, you can see that for a managed type to work with Problem 3: Replacement for ostream_iteratorI often use #include <vector> #include <algorithm> #include <iterator> #include "gcstl.h" using namespace System; using namespace std; int main() { //vector <String __gc*> v; //Problem 1 vector <gcroot<String __gc*> > v; v.push_back(S"bca"); v.push_back(S"bac"); v.push_back(S"abc"); //sort (v.begin(), v.end()); //Problem 2 sort (v.begin(), v.end(), gc_less<String __gc*>()); //copy (v.begin(), v.end(), //ostream_iterator<String __gc*>(wcout, S" ")); //Problem 3 copy (v.begin(), v.end(), textwriter_iterator<String __gc*> (Console::Out, S" ")); } Internally, Notice that I didn't provide a managed counterpart for Problem 4: Using STL algorithms with .NET collectionsTo make STL algorithms work with .NET collections, I created a template wrapper #include <algorithm> #include "gcstl.h" using namespace System; using namespace std; int main() { String __gc* st_array[] = {S"bca", S"bac", S"abc"}; gc_collection<Array __gc*, String __gc*> cont(st_array); gc_collection<Array __gc*, String __gc*>::const_iterator it = find_if(cont.begin(), cont.end(), bind2nd(gc_equal_to<gcroot<String __gc*> >(),S"abc")); if (it != cont.end()) Console::WriteLine(*it); }
I designed
Minimalist as is, References
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||