Search
Duplicate
🏏

STL.NET Primer (2/4)

Category
S/W 엔지니어
Tags
C++
C++/CLI
STL
STL.NET
.NET
Stanley Lippman
STL/CLR
Created time
2005/03/22
STL.NET Primer (1/4)에서 이어지는 글입니다.
이 컬럼은 STL.NET Primer란 제목으로 MSDN에 포스팅된 글을 번역한 것입니다.

행복한 고민 : 무엇을 선택해야 하는가?

CLI 타입으로 이루어진 컬렉션을 조작하는 데 있어 Visual C++ 프로그래머가 선택 가능한 컨테이너 라이브러리에는 세 가지가 있는데, 이들 라이브러리는 세 가지의 타입 매개변수화(type parameterization) 모델에 각각 기반하여 만들어진 것입니다. 아래의 리스트는 각 모델에 해당하는 코드 샘플과 함께 이들 라이브러리를 요약한 것입니다.
오리지널 System::Collections 라이브러리는, 모든 CLI 타입의 기초 클래스(base class)인 Object를 통해 요소 타입을 저장하는 데에 기반을 둡니다. 그 예로, 아래에는 IList 인터페이스를 구현하는 ArrayList가 있습니다. 이 타입은 Object 타입의 배열을 나타내며, 이 예제에서는 String 타입의 요소를 담고 있습니다.
void objectCollection() { using namespace System::Collections; ArrayList ^as = gcnew ArrrayList; 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 ) { // 명시적인 다운캐스트가 필요합니다. String^ item = safe_cast( as[ index ]); as->RemoveAt( index ); } as->Remove( "Rabbit" ); Console::WriteLine( " ArrayList holds {0} elements: ", as->Count ); IEnumerator^ is = as->GetEnumerator(); While ( is->MoveNext() ) Console::WriteLine( is->Current ); }
C++
복사
새로운 컨테이너 라이브러리는 CLI Generic 메커니즘에 기반을 두고 있습니다. 이 라이브러리는 System::Collections::Generic 네임스페이스에서 찾을 수 있죠. 이 라이브러리는 Visual Studio 2005 베타 1에서 선보였는데, 최종판이 배포되기에 앞서 변경이 가해지리라 예상됩니다. Collection<T>는 구체화될 지네릭 기반 클래스(concrete generic base class)로서, 사용자들은 이 클래스를 기초 클래스로 하여 그들만의 특화된 컨테이너 클래스를 파생시킬 것입니다. 다음은 위의 예와 동일한 내용이 담긴 지네릭 버전의 예제 코드입니다.
void genericCollection() { using namespace System::Collections::Generic; Collection<String^> ^cols = gcnew Collection<String^>; cols->Add( "Pooh" ); cols->Add( "Piglet" ); cols->Add( "Eeyore" ); cols->Add( "Rabbit" ); // 콜렉션에 관계된 정렬 메서드가 없습니다. 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 ) { // 다운캐스트가 필요 없습니다 ... String ^item = cols[ index ]; cols->RemoveAt( index ); } cols->Remove( "Rabbit" ); Console::WriteLine( " Collection holds {0} elements:", cols->Count ); IEnumerator<String^> ^is = cols->GetEnumerator(); while ( is->MoveNext() ) Console::WriteLine( is->Current ); }
C++
복사
STL.NET에서 사용하는 타입 매개변수화(type parameterization) 모델은 매우 다른데, 바로 이 모델이 다음 절의 주제입니다. 다음의 구현 코드는 String 컨테이너로서, 아래에서 좀더 깊게 파고들 내용입니다.
#include <cli/vector> #include <algorithm> void stlCollection() { vector<String^> ^svec = gcnew vector<String^>; 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::iterator iter = find( svec->begin(), svec->end(), "Pooh" ); if ( iter != svec->end() ) { // 다운캐스트가 필요 없습니다 ... String ^item = *iter; svec->erase( iter ); } // 지네릭 알고리즘: remove ... remove(svec->begin(),svec->begin(),svec->end(),"Rabbit"); Console::WriteLine( " Collection holds {0} elements: ", svec->size() ); IEnumerator ^is = svec->GetEnumerator(); while ( is->MoveNext() ) Console::WriteLine( is->Current ); }
C++
복사

왜 STL.NET인가?

STL.NET에 대하여 파고들기에 앞서, 분명히 해두어야 할 사항을 짚고 가도록 하죠. 바로 다음과 같은 질문에 관한 것입니다 : 왜 Visual C++ 프로그래머는 언어 중립적 라이브러리인 System::Collections나 System::Collections::Generic보다, STL.NET 컨테이너 라이브러리를 선택하는 것이 좋을까?
보통, System::Collections 라이브러리를 피하게 되는 이유는 Visual Studio 2005에서 Generic 라이브러리를 제공하는 이유와 동일합니다. 즉, 매개변수화에 대한 Object 모델은 타입 정보를 손실함으로 인하여 복잡하고도 안전하지 않다는 것이죠. 16개 혹은 그 이하의 요소를 가진 컨테이너에서는 버블 소트(bubble sort)가 문제없는 것처럼, 간단하게 사용할 때에는 이 모델도 괜찮습니다. 하지만 여러분의 애플리케이션이 실세계의 문제를 다루는 경우라면, 여러분에게는 좀더 정교한 해결책이 필요하게 될 것입니다.
따라서, Visual C++ 같은 시스템 프로그래밍 언어를 위한 대안은 STL.NET과 System::Collections::Generic 라이브러리로 좁혀집니다. 그렇다면, 왜 Visual C++ 프로그래머는 이 두 라이브러리 중 STL.NET을 선호해야 할까요? 그리고 이는 나머지 우리의 프로그램을 다른 .NET 언어로부터 격리시키는 꼴은 아닐까요? 이는 유효한 질문일 뿐만 아니라, 답변받을 만한 가치가 있는 질문입니다.
첫 번째 답변은 확장성(extensibility)입니다. Alex Stepanov가 발명한 STL의 원 디자인 패턴은 알고리즘과 컨테이너를 각기 다른 두 영역(domain space)로 나눕니다. 따라서 여러분은 모든 종류의 컨테이너에 적용될 알고리즘을 추가할 수 있거나, 그 알고리즘이 적용될 컨테이너들을 추가할 수 있습니다. 하지만 Generic 라이브러리는 좀더 제한적인 컨테이너 모델이며, 이 사실은 우리를 두 번째 답변으로 이끕니다.
두 번째 답변은 통일성(unification)입니다. 실전의 C++ 프로그래머들은 기존의 코드 몸체뿐만이 아니라, 이 라이브러리도 함께함으로써 전문적 기술을 익혀왔습니다. 우리가 원하는 바는 (.NET으로의) 이주로(migration path)를 제공하는 데 있어 기존의 코드뿐만 아니라, 몸에 익숙해진 기존의 기술도 함께 할 수 있도록 하는 것입니다. 여러분이 C++로 프로그래밍을 할 때에 STL에 의존해왔을 경우 .NET 하에서 STL을 사용 못하게 된다면, 여러분은 이를 크나큰 손실로 여길 것입니다(적어도 저의 경험으로는 그랬습니다). 이러한 견해는 저와 의견을 나눠온 많은 고급 C++ 프로그래머들에게서 이미 제기되었던 사항이며, 이로 인해 그들은 .NET으로 이주하는 것을 보류했다고 말해왔습니다.
세 번째 답변은 성능(performance)입니다. 하지만 C++ 프로그래머는 성능에 관한 주제에 대해선... 흠, 말하자면, 짜증날 정도로 예민하기 때문에, 이 연재물 중 적절한 시점에서 다시 다루도록 하겠습니다.
마지막으로, 남은 질문, "좋아요, Stan. 지금까지 모두 좋았다고요. 하지만 이는 C++ 프로그래머와 C++/CLI 프로그램을 나머지 다른 .NET 커뮤니티로부터 고립시키게 되는 일이 아닌가요?" 이에 대한 답변은, 제가 믿기로는, '아니오'입니다. Anson Tsao, Martyn Lovel, P.J. Plauger를 비롯한 STL.NET 아키텍트들은 이 사안에 대해 심사숙고를 해왔으며, 우리는 우리의 능력, 즉 IEnumeratorIList, 그리고 ICollection에 대한 지원을 통해 다른 .NET 언어와 상호운용을 이뤄낼 수 있다는 데에 확신을 가집니다. 이어질 저의 컬럼 중 하나에서는 이 사항에 대하여 깊게 다룰 것입니다.
STL.NET Primer (3/4)으로 계속됩니다.