JAL Computing

C++COMProgramming .NET Mac Palm CPP/CLI Hobbies

 

Home
Up

STL in a Managed Environment

The STL/CLI is now available in the Visual Studio 2008 Express Edition.
First we exercise the CLI Vector! Note the decision to use reference semantics for CLI vectors and value semantics for std vectors.

// TestSTLVector.cpp : main project file.

#include "stdafx.h"
#include <vector>
#include <string>
#include <cliext/vector>
#include <cliext/algorithm>
#include <cliext/adapter>
#include <iostream>

using namespace System;
using namespace cliext;  // STL/CLR 
using namespace System::Runtime::InteropServices;
using namespace System::Diagnostics;

ref class Molecue {
private:
	String^ name;
public:
	Molecue(): name(nullptr){}  // default constructor	
	Molecue(String^ name){this->name= name;}  // constructor with a parameter
	Molecue(const Molecue% orig) : name(orig.name) {
		Console::WriteLine("Copy Constructor called.");
	} // STL required copy constructor 
	Molecue% operator=(const Molecue% orig) // STL required assignment operator
	{
		if (this != %orig){  // % -> tracking reference
			name= orig.name;
			Console::WriteLine("Assignment operator called.");
		}
		return *this;  // support assignment chaining
	}
	~Molecue() {
		Console::WriteLine("Destructor called.");
	}  // STL required destructor
	
	property String^ Name{
		String^ get() {return name;}
	}
};
int main(array<System::String ^> ^args)
{
    Console::WriteLine(L"Test STL/CLI Vector"); // L wide char
	// create objects with handles to objectss
	Molecue^ molecue1= gcnew Molecue(L"Hydrogen");
	Molecue^ molecue2= gcnew Molecue(L"Oxygen");

	// demonstrate use of handle, no call to the copy constructor
	Molecue^ alias2= molecue2;

	// demonstrate use of stack based semanitics, does call copy and assignment operator
	Molecue stack("Sodium");
	Molecue stack1= stack; // calls copy constructor
	Molecue stack2;
	stack2= stack;  // calls assignment operator

	// create/populate/iterate vector of handles to molecues
	vector<Molecue^>^ v= gcnew vector<Molecue^>;
	v->push_back(molecue1);
	v->push_back(molecue2);
	vector<Molecue^>::iterator it = v->begin(); 
	for (; it != v->end(); it++) {
		Console::WriteLine(it->Name);
	}

	// convert array of handles to Molecues to Vector of handles to Molecues
	array<Molecue^>^ array1= gcnew array<Molecue^>(2);
	array1[0]= molecue1;
	array1[1]= molecue2;
	vector<Molecue^>^ v2= gcnew vector<Molecue^>(array1);
	vector<Molecue^>::iterator it2 = v2->begin(); 
	for (; it2 != v2->end(); it2++) {
		Console::WriteLine(it2->Name);
	}

	// copy vector into a collection
	System::Collections::Generic::ICollection<Molecue^>^ iColl =
        make_collection<cliext::vector<Molecue^>::iterator>(
            v->begin() +0, // start offset 0
            v->end() -0);  // finish offset 0
	for each (Molecue^ m in iColl) {
		Console::WriteLine(m->Name);
	}

	Console::ReadLine();
    return 0;
}
 

Now we do some interop converting a std STL Vector of std strings to a CLI Vector of managed Strings^.

// TestInterop.cpp : main project file.
#include "stdafx.h"
#include <vector>  // std vector
#include <string>  // std string
#include <cliext/vector>
#include <cliext/algorithm>
#include <cliext/adapter>

using namespace System;
using namespace cliext;  // STL/CLR 
using namespace System::Runtime::InteropServices;   // Marshal

class Util {
public:
	/////////////////////////////////////////////////////////
	//  ** ConvertSS2MS  **                                //
	// Converts std::string to managed String^             //
	// Parameters constant std::string in by ref           //
	// Returns String^ out                                 //
	// Static Public Class method                          //
	// Internally converts to most common denominator      //
	// char* on heap using new and delete                  //
	// std::string ref in cannot be null, but may be empty //
	// Returns empty string on exception                   //
	// JAL 12/04/08                                        //
	/////////////////////////////////////////////////////////

	static String^ ConvertSS2MS(const std::string& in) {
			String^ out= L""; // L wchar_t typedef unsigned short
			char* str=0;
			size_t size= strlen(in.c_str()) +1; // +1 for null terminator
			
			try {
				//const char *p= in.c_str();  // use p immediately
				//out= Marshal::PtrToStringAnsi(static_cast<IntPtr>(p)); // error on const char *
				str= new char[size]; // null terminated
				strcpy_s(str,size,in.c_str());  // create longer lived copy in non const char array 
				// strcpy_s has new security enhancements over strcpy, size includes null char
				out= Marshal::PtrToStringAnsi(static_cast<IntPtr>(str));  // or safe_cast?
			}
			catch(...) { // eat the exception
				out= L"";  // returns empty string on exception
			}
			finally {  // clean up memory
				if(str) {
					delete [] str;  // release char[] on unmanaged heap, delete [] calls destructors
				}
			}
			return out;
	} // end ConvertSS2MS
}; // end class Util

int main(array<System::String ^> ^args)
{
    Console::WriteLine(L"Test STL/CLI Vector Interop"); 

	// test standard STL to STL/CLI
	// fill std vector with std strings
	std::vector<std::string> stdVector;  // value semantics
	stdVector.reserve(2);
	stdVector.push_back("Hello");
	stdVector.push_back("World");

	// create CLI vector of type managed Strings^
	vector<String^>^ cliVector= gcnew vector<String^>;  // ref semantics

	// possible thread safety issue here
	{
		size_t size= stdVector.size();
		cliVector->reserve(size);
		
		// fill CLI vector with managed Strings^
		std::vector<std::string>::iterator itStd= stdVector.begin();
		for(;itStd != stdVector.end();itStd++) {
			cliVector->push_back(Util::ConvertSS2MS(*itStd));
		}
	}


	// display contents of CLI vector
	vector<String^>::iterator itCli= cliVector->begin();
	for(;itCli != cliVector->end();itCli++) {
		Console::WriteLine(*itCli);
	}

	// test for runtime errors
	//String^ out= Util::ConvertSS2MS(std::string(""));  // succeeds with empty string
	//Util::ConvertSS2MS(0); // fails with null ptr

	Console::ReadLine();
    return 0;
}

Have fun!

Send mail to [email protected] with questions or comments about this web site. Copyright © 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 © 
Last modified: 08/04/09
Hosted by www.Geocities.ws

1