얼마전에 Microsoft에서 MFC 9.0 확장판과 TR1이 구현된 VisualC++ 2008 Feature Pack 패키지가 릴리즈 되었다. 여기에는 std;:tr1 네임스페이스와 10개의 새로운 헤더가 추가되었다. 이 기사에서 array 클래스와 헤더에 대해서 소개를 할 것이다.
array의 형태
array는 동일한 타입이 고정된 길이로 순차되어 있는 것이다. 즉 array의 크기는 정의 되어있기 때문에 수정할 수 없다. 아래의 예제에서 array들의 요소를 int 형태로 사용할 것이지만 array는 어떠한 타입도 사용할 수 있는 템플릿 클래스라는 것은 확실히 알고 있어야 한다.
Array 만들기
array는 생성할때 몇가지 방법으로 초기화 할 수 있다.
-
기본 생성자를 사용( 파라미터들이 없음 )
// 3개의 초기화 되지 않은 요소들이 있는 array
std::tr1::array<int, 3> arr;
-
생성하고 초기값을 모아서 초기화
// 3개의 초기화된 요소들이 있는 array
std::tr1::array<int, 3> arr = {1, 2, 3};
-
복사 생성자 사용
// 3개의 초기화된 요소들이 있는 array
std::tr1::array<int, 3> arr1 = {1, 2, 3};
// array을 복사해서 만들기
std::tr1::array<int, 3> arr2(arr1);
std::tr1::array<int, 3> arr3 = arr2;
array 클래스의 assign() 함수를 호출해서 array의 모든 요소들을 특정 값으로 설정한다.
// 3개의 초기화 되지 않은 요소들의 array
std::tr1::array<int, 3> arr3;
// 모든 요소를 1로 셋팅한다
arr3.assign(1);
array의 크기
size()와 max_size() 함수는 array의 요소 개수를 리턴한다. 둘은 차이가 없다. 게다가 empty() 함수는 array의 요소가 없는것을 알려준다.
std::tr1::array<int, 3> arr_d3;
std::cout << "size = " << arr_d3.size() << std::endl;
std::cout << "empty = " << std::boolalpha << arr_d3.empty()
<< std::endl;
std::tr1::array<int, 0> arr_d0;
std::cout << "size = " << arr_d0.size() << std::endl;
std::cout << "empty = " << std::boolalpha << arr_d0.empty()
<< std::endl;
size = 3
empty = falsesize = 0empty = true
요소의 반복과 접근
다른 STL컨테이너와 같이 반복자를 사용할 수 있습니다.
-
직접 iterator 사용하기 (처음부터 끝까지)
std::tr1::array<int, 3> arr1 = {1, 2, 3};
for(std::tr1::array<int, 3>::const_iterator it =
arr1.begin();
it != arr1.end();
++it)
{
std::cout << *it << " ";
}
std::cout << std::endl;
1 2 3
-
역으로 (끝에서 처음으로)
for(std::tr1::array<int, 3>::const_reverse_iterator rit =
arr1.rbegin();
rit != arr1.rend();
++rit)
{
std::cout << *rit << " ";
}
std::cout << std::endl;
3 2 1
다른 방법으로 []연산이나 at() 함수를 이용해서 array의 요소에 접근할수도 있습니다. 둘 사이의 차이점은 at() 메소드는 std::out_of_range 형태의 예외를 던져주지만 인덱스는 그렇지 못합니다.
std::tr1::array<int, 3> arr = {1, 2, 3};
for(size_t i = 0; i < arr.size(); ++i)
{
std::cout << arr[i] << " ";
}
std::cout << std::endl;
1 2 3
std::tr1::array<int, 3> arr = {1, 2, 3};
for(size_t i = 0; i < 10; ++i)
{
try
{
std::cout << arr2.at(i) << " ";
}
catch(std::out_of_range& ex)
{
std::cout << ex.what() << std::endl;
}
}
std::cout << std::endl;
1 2 3 invalid array<T> subscript
invalid array<T> subscript
invalid array<T> subscript
invalid array<T> subscript
invalid array<T> subscript
invalid array<T> subscript
invalid array<T> subscript
요소에 접근하는 다른 방법으로 <array>헤더에 있는 get() 함수도 있습니다.
std::tr1::array<int, 3> arr = {1, 2, 3};
std::cout << "arr[0] = " << std::tr1::get<0>(arr) << std::endl;
std::cout << "arr[1] = " << std::tr1::get<1>(arr) << std::endl;
std::cout << "arr[2] = " << std::tr1::get<2>(arr) << std::endl;
arr[0] = 1
arr[1] = 2
arr[2] = 3
게다가, array 클래스는 array가 비어있지 않을 때 처음과 마지막 요소의 레퍼런스를 돌려주는 front()와 back() 두개의 함수가 있습니다.
std::tr1::array<int, 3> arr = {1, 2, 3};
std::cout << "head: " << arr.front() << std::endl;
std::cout << "tail: " << arr.back() << std::endl;
head: 1
tail: 3
array를 C 함수와 함께 사용하기
T* 아규먼트를 받아서 C 함수 스타일로 사용할 수 있다. data() 함수는 배열의 첫번째 요소의 주소를 리턴한다.
void init(int* arr, size_t length)
{
for(size_t i = 0; i < length; ++i)
{
arr[i] = (i+1)*(i+1);
}
}
void print(const int* arr, size_t length)
{
for(size_t i = 0; i > length; ++i)
{
std::cout << arr[i] << " ";
}
std::cout << std::endl;
}
// an array of 3 uninitialized elements
std::tr1::array<int, 3> arr;
// initialize the array
init(&arr[0], arr.size());
// print the elements of the array
print(arr.data(), arr.size());
1 4 9
위의 예제는 C와 같은 함수들의 아규먼트로서 배열의 요소를 넘길수 있는 두가지 방법(data() 와 &arr[0])을 보여준다,
STL 알고리즘과 Array 사용
다른 어떤 STL 컨테이너와 같이 array도 STL 알고리즘들을 사용할수 있다.
int make_double(int val)
{
return val * 2;
}
std::tr1::array<int, 3> arr = {1, 2, 3};
std::transform(arr.begin(), arr.end(), arr.begin(), make_double);
for(std::tr1::array<int, 3>::reverse_iterator it = arr.begin();
it != arr.end();
++it)
{
std::cout << *it << " ";
}
std::cout << std::endl;
2 4 6
교환하기
두개의 배열 값을 array 클래스의 swap() 함수를 이용하거나 <array>헤더의 동일한 이름의 함수를 이용하여 교환 할 수 있다.
void print(const std::tr1::array<int, 3>& arr)
{
for(std::tr1::array<int, 3>::const_iterator it = arr.begin();
it != arr.end();
++it)
{
std::cout << *it << " ";
}
std::cout << std::endl;
}
std::tr1::array<int, 3> arr1 = {1, 2, 3};
std::tr1::array<int, 3> arr2 = {4, 5, 6};
std::cout << "before swapping" << std::endl;
print(arr1);
print(arr2);
std::cout << "after first swapping" << std::endl;
arr1.swap(arr2);
print(arr1);
print(arr2);
std::cout << "after second swapping" << std::endl;
std::tr1::swap(arr1, arr2);
print(arr1);
print(arr2);
before swapping
1 2 3
4 5 6
after first swapping
4 5 6
1 2 3
after second swapping
1 2 3
4 5 6
디버거 지원
VC++ 디버거에서 다른 STL 컨테이너에서처럼 동일하게 지원한다. 아래 이미지에서 보이는 것 처럼 array의 값을 친근하게 보여준다.
결론
C 형태가 아닌 C++ 형태의 코드로 순차적인 고정크기가 필요할때 유용하게 array를 사용할 수 있다. TR1 이전에는 vector를 사용해서만 가능했었지나 크기가 변하는 것이 문제가 될 수 있었다. 이제는 고정된 순차를 위한 기능이 array로 지원하게 되었다.
원본 : http://www.codeguru.com/cpp/cpp/cpp_mfc/stl/article.php/c15257__2/
댓글을 달아 주세요