It has been jokingly suggested that when a C++ programmer is asked how to accomplish a given task, he or she will provide a list of a dozen or more potential solutions, and then proceed to outline the problem with each in excruciating detail. Visual C++ 2005, through the C++/CLI language bindings, introduces the concept of generics, allowing C++ programmers to further enhance their reputation as the programmers with the largest arsenal of language constructs. Brent Rector covered the differences between .NET generics and C++ templates in an excellent article in June 2004. One of the article’s key points is that, despite the strong syntactic similarities, generics and templates are implemented very differently, and they don’t have any built-in compatibility. If you haven’t read Brent’s article, it is worth doing so now, because this article builds upon a number of the themes it covers.
The difference between templates and generics leads to the question that every C++ programmer who wants to target .NET will end up asking: Which technology should I pick? Those who have developed with C++ for a number of years, particularly C++ in its Visual C++ format, will probably already know the answer: Both technologies offer excellent features, neither technology is a superset of the other, and the right technology depends on the given task. In short, neither technology will cover you in all situations. This is the same dilemma that has plagued Visual C++ programmers over the years: Win32 or MFC or ATL or WTL (or console); COM or C-style DLLs; #import or CComPtr?
Leverage C++ Skills for .NET Development
In the past, Visual C++ has offered some technologies that have enabled STL collections to work with other technologies. The Active Template Library shipped with a templated class called CComEnumOnSTL, which allowed a Visual Basic client to use For Each to enumerate over the contents of an STL collection maintained by a C++ COM server. While this level of integration was rather shallow, it did prove useful in a number of limited situations. Building on the same theme, STL.NET offers C++ programmers an extension to the standard STL library. This extension allows the STL collections used internally in a C++/CLI assembly to be exposed to other .NET assemblies as generic collections.
The STL.NET collections offer the same interface as the standard STL collection classes, so there is no learning curve for a C++ developer who is familiar with the standard STL collection classes and algorithms that are available today. The header files for STL.NET are located in a folder called Cliext off the main VCinclude folder when Visual C++ 2005 is installed. So, to use a STL.NET collection such as vector, the header file <cliext/vector> rather than the standard <vector> needs to be included. The STL.NET collections are contained in the cliext namespace rather than the std namespace used by the standard STL collections.
Author Note: Before drilling too deeply into the details of STL.NET, it is worth briefly looking at how to get it, and Microsoft’s plans for its release. STL.NET ships with the Visual Studio Team System release of Visual Studio.NET 2005 Beta 2, and it is also contained in the June Community Technology Preview (CTP) release of Visual Studio.NET 2005. The C++ team is still working on ways to make STL.NET easier to use and improving its performance, and STL.NET likely won’t ship with the Release to Manufacturing (RTM) of Visual Studio 2005 .NET. At some post-RTM stage, STL.NET will be available as a Web download. With significant changes to STL.NET still to come, this article won’t drill deeply into the STL.NET collections. It instead takes a higher-level look at why STL.NET will be useful.
Bridging Templates and Generics
The task of bridging the worlds of templates and generics is fairly difficult. Templates are a C++-only concept that does not exist past compile time, whereas generics are a .NET concept that is maintained in the compiled assembly and available to all .NET languages. The solution STL.NET uses is implementing the collections as C++ template classes that are also .NET reference types that implement the generic ICollection interface. The declaration of the STL and STL.NET vector declarations illustrates this design decision:
//STL vector declaration
class _Ax = allocator<_Ty> >
//STL.NET vector declaration
ref class vector
A number of key differences exist between the two declarations, beside the implementation of the generic interface: the STL.NET vector doesn’t have the ability to specify an allocator, and it simply will use a call to gcnew to allocate a new element if required. The STL.NET collections are declared using the ref keyword, which means that they are .NET reference types, and they will be allocated on the .NET managed heap.
Apart from a few differences in the way a STL.NET collection is declared, which relate to the syntactic differences between C++/CLI and standard C++, using a STL.NET collection is exactly the same as using the same STL collection. The following console application declares a vector of objects, then adds a few elements of different types to the collection:
using namespace System;
using namespace cliext;
int main(array<System::String ^> ^args)
vector<Object^>^ v = gcnew vector<Object^>;
v->push_back(nullptr); //first element is empty
v->push_back(gcnew Object()); //second element is a plain Object
v->push_back(1); //third element is boxed integer
v->push_back(“Element Four”); //fourth element is a string
This code sample illustrates one of the key benefits of STL.NET: a very familiar set of collection classes. Another key benefit is the ability to take a populated collection and use two different programming models against it. Using the collection populated in the first code sample, the presence of the integer one can be determined by using the STL find algorithm:
//use as STL collection
bool containsOneSTL = find( v->begin( ), v->end( ), 1 ) != v->end();
Alternatively, the .NET generic ICollection interface can also be used to implement the same logic:
//use as .NET collection
bool containsOnedotNet = v->Contains(1);
The ability to use the same collection class against both STL and .NET algorithms—without copying the contents or providing bridging functions—allows the C++/CLI programmer to choose the best function and library for any collection manipulation task.
The final key benefit of STL.NET is the ability to seamlessly expose STL.NET collections to .NET assemblies written in C# or VB.NET. As STL.NET collections implement the generic ICollection interface, there is no loss of type-safety. Because STL.NET collections use managed memory to store the collection’s elements, there is no loss in performance or code security from interacting with a C++/CLI assembly that exposes STL.NET collections.
C++ Programmers’ Ticket to the .NET Realm
STL.NET represents an important part of the Visual C++ product. STL.NET allows C++ programmers to leverage their existing skills and experience, and employ an incredibly powerful library of collections and algorithms without being shut off from the rapidly growing world of .NET.
Hopefully STL.NET is just the beginning of technologies that allow C++ to act as a first-class .NET language while preserving the language’s proud heritage.
About the Author
Nick Wienholt is an independent Windows and .NET consultant based in Sydney, Australia. He is the author of Maximizing .NET Performance from Apress, and specializes in system-level software architecture and development with a particular focus on performance, security, interoperability, and debugging. Nick can be reached at [email protected].