title: "**STL.NET Primer (3/4)**"
description: "**STL.NET Primer (3/4)**"
cleanUrl: /sw-engineer/stl-net-primer-3
ogImage: ""
floatFirstTOC: right
STL.NET Primer (2/4) 에서 이어지는 글입니다.
<aside> 💡 이 컬럼은 STL.NET Primer란 제목으로 MSDN에 포스팅된 글을 번역한 것입니다.
</aside>
STL.NET 을 알아가는 데는 두 가지 방법이 있습니다: 하나는 STL과 STL.NET의 차이점을 알아보는 것이고, 다른 하나는 STL과 STL.NET이 공통점을 알아보는 것입니다. 이 둘의 차이점을 나열하는 것은 이미 STL을 맛보았던 사람에게만 와닫을 법하기 때문에, (독한 연기로 질식시키는 듯한) 라이브러리의 낯선 부분에 대한 설명은 피하는 것이 좋을 듯 합니다. 말하자면, 컨테이너의 세밀한 특징, 그리고 System 컬렉션 라이브러리와의 상호운용 원리라는 난해한 부분에 대해서는 설명을 자제하겠다는 뜻입니다. 물론 이들 사항도 흥미로운 부분이긴 합니다. 하지만 이들 사항에 대한 설명은 이 라이브러리에 깊이 빠진 새로운 누군가의 몫으로 남겨두는 편이 더 났지 않을까요? 이것이 바로 아래에 이어질 내용 - 입문자를 위한 내용- 에 담긴 저의 의도입니다. 이런 방법을 취함으로써 이 라이브러리에 처음 발을 내딛는 사람은, STL과 STL.NET 모두가 제공하는 확장된 모델, 즉 매개변수화된(parameterized) 컬렉션에 기분좋게 다가갈 수 있을 것입니다.
그렇다면 STL과 STL.NET이 공유하는 부분은 무엇일까요? 이 둘 모두 순차(sequential) 컨테이너와 연관(associative) 컨테이너이란 두 개의 기본 컴포넌트와 지네릭 알고리즘으로 구성되어 있다는 것입니다. (맞습니다. 여러분이 STL에 익숙한 개발자라면, 어떤 내용이 이어질지 알고 있을 것입니다. 그렇다 하더라도, 이 절은 기본 용어와 기반 지식을 설명하는 데 할애되었기 때문에, 그러한 여러분의 인내심을 요청하는 바입니다.) 지네릭 알고리즘은 컨테이너 타입에 직접적으로 운용되지 않습니다. 그 대신, 이들 알고리즘에 운용할 요소의 범위를 나타내는 반복자(iterator)가 넘어가는데, 통상 이들 반복자를 가리켜 first와 last라 칭합니다. 공식적으로 좌측 포함 간격(left-inclusive interval)이라 이름붙은 아래의 요소 범위 표기법은,
// "first와 last까지의 모든 요소를 포함하지만 last는
// 포함하지 않습니다." 라는 의미를 갖습니다.
[ first, last )
범위가 first
에서 last
까지지만 (first
와는 달리) last
는 포함되지 않음을 나타냅니다. first
와 last
가 같은 경우에는 그 범위 안에 어떠한 요소도 없다는 뜻입니다.
순차(sequential) 컨테이너에는 단일 타입으로 이루어진 정돈된 요소들이 담겨 있습니다. 가장 기본적인 순차 컨테이너는 vector
와 list
타입입니다. (세 번째 순차 컨테이너인 - '데크'라고 읽습니다 - 는 vector
처럼 동작하지만, 맨 앞 요소에 대한 효율적인 삽입과 삭제에 특화되어 있습니다. 예를 들어, 큐(queue)를 구현할 때는 vector
보다는 deque
가 더 났습니다.)
순차 컨테이너 타입를 참조하기에 앞서 해야할 것은, 다음의 헤더 파일 중에서 적절한 파일을 포함하는 것입니다.
#include <cli/vector>
#include <cli/list>
#include <cli/deque>
이들 헤더 파일에는 interface_vector
와 같은 공유되는 기초 인터페이스의 선언부와, generic_vector등의 이들 컨테이너의 형제뻘 컨테이너도 함께 담겨 있습니다.
STL.NET 컨테이너는 참조 타입입니다. 컨테이너 선언부에는 트래킹 핸들(tracking handle)이 있는데, 이는 자동적으로 nullptr
로 초기화됩니다. 그리고 우리는 gcnew 연산자를 이용하여 실제 컨테이너를 할당하게 됩니다. 이전 절에서 이미 이를 간단하게 보여주긴 했지만, 여기에 한번 더 명시하도록 하죠.
void f()
{
// 빈 vector를 할당합니다 . . .
vector<String^>^ = gcnew vector<String^>;
// 기본적으로 nullptr로 각각 설정되어 있는
// 10개 요소가 담긴 리스트를 할당합니다.
list<Object^>^ olist = gcnew list<Object^>( 10 );
// 트래킹 핸들은 nullptr로 자동 설정됩니다.
deque<int>^ ideck;
// 뭔가 흥미로운 일을 합니다 . . .
};
연관 컨테이너에 대한 선언법과 용법에 관해서는 이 연재물의 다음 컬럼에서 다루도록 하겠습니다.
연관 컨테이너는 요소의 보관과 되찾기(retrieval)에 대한 질의(query)를 효율적으로 지원합니다. 기본적인 두 가지 연관 컨테이너 타입은 map
과 set
이죠. map
은 key와 value 쌍으로 이루어져 있습니다. key는 검색을 위해 사용되고, value에는 저장하고 되찾아올 데이터가 담깁니다. 예를 들어, 전화번호부는 손쉽게 map
을 이용하여 나타낼 수 있는데, 여기서 key는 개개의 이름을 나타내고, value는 그 이름에 연관된 전화 번호를 나타냅니다.
map
은 자신의 기초를 이루는 트리 추상체(tree abstraction)을 이용하여 요소를 오름순으로 정렬합니다. hash_map
컨테이너는 되찾기(retrieval) 명령에 있어 좀더 효율적입니다. 하지만 hash_map
의 반복(iteration)은 다소 임의적인 순서(random order)로 각 요소에 접근(access)합니다. 만약 되찾기가 주된 목적이라면 hash_map
을 사용하는 편이 좋습니다.
set
은 단일 key 값들로 구성되며, 그 값이 존재하는지에 대한 질의(query)에 효과적입니다. 예를 들어, 텍스트 질의 시스템(text query system)을 만들 경우에는 텍스트에 담긴 단어들로 이루어진 데이터베이스를 구축하기 위해선 the, and, but등과 같은 제외시킬 일반 어휘 목록이 필요할 것입니다. 이 프로그램은 텍스트에 담긴 각 단어를 차례로 읽어, 읽어낸 단어가 제외 단어 목록에 있는지를 검사하고, 질의 결과에 따라 그 단어를 데이터베이스에 저장하거나 버릴 것입니다. set
뿐만 아니라, hash_set
이란 컨테이너도 있는데, 이들 간의 일반적 특징은 map
과 hash_map
간에 보이는 일반적 특징과 동일합니다.
map
과 set
에 담길 각 key는 각기 서로 달라야 합니다. 하지만 multimap
과 multiset
은 중복된 key를 허용합니다. 예를 들어, 위의 전화번호부는 한 개인에 속한 여러 사항이 기재될 수 있어야 할 것입니다. 바로 이 경우에 multimap
을 사용하면 됩니다. 이밖에도 hash_multimap
과 hash_multiset
이란 컨테이너가 있습니다.