|
STL in a Managed EnvironmentThe STL/CLI
is now available in the Visual Studio 2008 Express Edition. // 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 ©
|