体验STL.NET [翻译] zengyi820 2004-10-07 | |
为了更好的使STL适合.NET开发,Visual C++产品组,在2005版的Visual C++中重新设计了STL,并命名为STL.NET,从Beta1版本的产品中开始提供。 在STL.NET的设计中,STL的实现使用了CLI泛型和C++模版机制。2005版本的C++将加入C++/CLI动态编程的支持,应当会成为最能够满足程序员设计的语言。 给予程序员丰富的选择 总共有三个容器库可供程序员用于操作CLI类型,这三个容器库建于三种类型参数化模型之上。 原先元素类型存储的Systems::Collection 库是基于CLI类型中的对象基类来实现的。如下的 ArrayList实现了IList接口。它代表类型对象的数组,在本例中用于控制String类型的元素。(这里采用版本2的语法来实现) void objectCollection() { using namespace System::Collections; ArrayList ^as = gcnew ArrayList; as->Add( "Pooh" ); as->Add( "Piglet" ); as->Add( "Eeyore" ); as->Add( "Rabbit" ); as->Sort(); Console::WriteLine( "ArrayList holds {0} elements: ", as->Count ); for ( int i = 0; i < as->Count; i++ ) Console::WriteLine( as[ i ] ); int index = as->IndexOf( "Pooh" ); if ( index != -1 ) { //需要一个清晰地downcast String^ item = safe_cast as->RemoveAt( index ); } as->Remove( "Rabbit" ); Console::WriteLine( "\nArrayList holds {0} elements: ", as->Count ); IEnumerator^ is = as->GetEnumerator(); while ( is->MoveNext() ) Console::WriteLine( is->Current ); } 现在我们引入了一个基于CLI泛型机制的新的容器库。可以在System::Collections::Generic 命名空间中找到。这是在Visual Studio 2005 Beta1中的实现,在最终的发布版当中可能会有所改变。Collection void genericCollection() { using namespace System::Collections::Generic; Collection gcnew Collection cols->Add( "Pooh" ); cols->Add( "Piglet" ); cols->Add( "Eeyore" ); cols->Add( "Rabbit" ); //没有与Collection关联的Sort方法 Console::WriteLine( "Collection holds {0} elements: ", cols->Count ); for ( int i = 0; i < cols->Count; i++ ) Console::WriteLine( cols[ i ] ); int index = cols->IndexOf( "Pooh" ); if ( index != -1 ) { //不需要downcast…… String ^item = cols[ index ]; cols->RemoveAt( index ); } cols->Remove( "Rabbit" ); Console::WriteLine( "\nCollection holds {0} elements:", cols->Count ); IEnumerator while ( is->MoveNext() ) Console::WriteLine( is->Current ); } STL.NET提供了一个与以往设计风格迥异的类型参数化模型,我们将在下个话题中谈到 。下面是String容器的实现。 #include #include void stlCollection() { vector svec->push_back("Pooh"); svec->push_back("Piglet"); svec->push_back("Eeyore"); svec->push_back("Rabbit"); //泛型算法:sort sort( svec->begin(), svec->end() ); Console::WriteLine( "Collection holds {0} elements: ", svec->size() ); for ( int i = 0; i < svec->size(); i++ ) Console::WriteLine( svec[ i ] ); //泛型算法:find vector find( svec->begin(), svec->end(), "Pooh" ); if ( iter != svec->end() ) { //不需要downcast…… String ^item = *iter; svec->erase( iter ); } //泛型算法: remove…… remove( svec->begin(), svec->end(), "Rabbit" ); Console::WriteLine( "\nCollection holds {0} elements:", svec->size() ); IEnumerator while ( is->MoveNext() ) Console::WriteLine( is->Current ); } 为什么要选用STL.NET? 在我们深入STL.NET之前,让我们首先来简要地回答一个不可避免的问题:Visual C++程序员为什么要选用STL.NET容器类而不是语言中立的系统:Collections或者System::Collections::Generic 库? 立即放弃System::Collections库和Visual Studio 2005决定提供泛型裤的原因是一样的:由于类型信息的丢失,经常会造成参数化对象模型非常的复杂并且不安全。在简单的使用中,例如在容器中装有16个或者更少的元素,进行冒泡排序的时候还可以使用。但当你的应用程序涉及到真实世界的问题的时候,你就必须要提供一个更为完善的解决方案了。 所以,STL.NET和System::Collections::Generic库便成为如Visual C++这样的系统级程序设计语言的备选方案。为什么Visual C++程序员应当偏爱于STL.NET呢?这不就使我们的程序与其他的.NET语言隔离开了么?这是一个很现实的问题,并且也值得作出一个答复。 回复之一是“可扩展性(extensibility)”。最初STL的设计模式是由Alex Stepanov发明的, 他将算法和容器存放在了不同的域空间中。这样用户就可以将所有容器都适用的算法添加到算法集当中去,或者将每个算法都可以应用的容器添加到容器集当中去。泛型库是一个更为传统的模型。这就引出了我们第二个回复。 第二个回复是“统一性(unification)”。现在正在使用C++的程序员使用这个库和现有的代码的水平已经达到了专家水准。我们不仅仅希望能够提供一个对现有代码迁移的途径,同时也希望使程序员们积累下来的专家经验仍然适用。如果在你原来进行C++编程的时候依赖于STL,并且很难想象一个C++程序员不依赖于STL,那么它在.NET中的消失会使你感到是一个很大的失误—至少这是我曾经的体会。与我曾经交流过的很多C++专家都曾经提到过这个问题,并且因此表示对迁移到.NET持保留态度。 第三个回复是“性能”。但是C++程序员对于讨论性能这个话题早已显得不愿意再提这些陈词滥调,我这里只是一笔带过—在后续的文章中将深入讨论。 最后问题是。这些做的都非常棒并且非常好Stan, 但是这不是将C++程序员和C++/CLI程序与.NET社群的其它部分隔阂开了么?对于这个问题的回答,我认为是一个非常简单的“不”。STL.NET的体系架构师,包括Anson Tsao, Martyn Lovell, 和P.J. Plauger, 已经非常慎重地考虑了这个问题,通过对IEnumerator, IList, 和ICollection的支持,我们对于STL.NET能够和其它.NET 语言共同操作的能力非常有信心。我们将在后续的系列文章中深入的讨论。 定义一个公共基础 深入了解并使用STL.NET的方法有两种:一种途径是可以通过了解STL和STL.NET的区别来掌握。另外一种途径是通过了解他们有哪些共性。虽然那些有STL丰富使用经验的人来说似乎需要一张“区别清单”,然而这并不能使你从那些不熟悉的库的乌烟瘴气中逃离出来,所以说,当我们放慢脚步,深入这些或那些容器以及他们是如何与系统集合库(System collection libraries)互操作等这样的深奥角落的时候—虽然这些都是非常整洁优雅的,但我们直接的去了解这些新的内容不是更好么?至少在下面的简短介绍部分我希望大家是这样做的。通过这种方法,对于那些新手来说就可以对STL和STL.NET提供的参数化集合的扩展模型有一个了解。 那么STL和STL.NET都有哪些共性呢?这两者都包括两个主要的组件:顺序式(Sequential)和关联式(associative)容器类型,以及一个泛型算法集。(是的,如果你是一个经验丰富的STL开发者,你就应当知道我下面要讨论什么。同样,两者具有同样的术语和背景,所以你得耐心点。) 泛型算法不直接操作容器类型。取而代之的是,我们使用了一个迭代器来成对的标识用于操作的元素范围。元素范围符号(正式的术语为左包含区间)如下所示: // 读作:包含first直至但是不包括last [ first, last ) 这表明了范围是从first开始以last结束但是不包含last。当first等于last的时候这个范围就是空了。 顺序式容器中存储了单独类型元素的序列集。vector和list类型是两个主要的顺序式容器。(第三个顺序式容器是deque—发音deck—提供了vector同样的功能,但是用于对高效插入和删除第一个元素这种特殊情况。一般我们首选deque而不是vector,例如一个队列的实现。) 我们在访问一个连续容器类型之前,我们必须包含进合适的头文件,如下所示: #include #include #include 这些头文件同时也包含了共享基类接口的声明,例如interface_vector,以及泛型在容器中的应用,例如generic_vector。 STL.NET的容器是引用类型的;容器的声明中会有一个追踪句柄—它会自动的初始化为nullptr。我们通过gcnew操作符分配一个实际的容器。我们在前面的小节中曾经简单地提到过,现在我来详细地解释一下: void f() { //分配一个空向量(vector)…… vector //分配一个含有10个元素的表(list) //每一个值默认都被设为nullptr list |
本文地址:http://com.8s8s.com/it/it43677.htm