본문 바로가기

[Algorithm] STL 배열(Array)

Kwonriver 2022. 1. 15.
728x90

STL이 지원하는 컨테이너 클래스인 array<>은 정적 배열을 나타낸다.

일반적인 C 배열을 클래스화 시켜 STL 컨테이너의 인터페이스를 제공한다.

배열은 크기가 같은 요소들이 연속적으로 모여 있는 것이기 때문에 크기를 변경할 수 없다.

요소의 값을 바꾸는 작업만 가능하다.

 

배열을 사용하기 위해서는 <array> 헤더파일을 인클루드 해야한다.

#include <array>

namespace std에 정의 되어 있기 때문에 사용하려면 std::array<>로 사용한다.

using namespace std를 사용하면 안그래도 된다.

 

 

array는 템플릿 클래스이므로 어떠한 데이터형도 가질 수 있다.

두 번째 매개변수는 앞으로 가질 요소의 개수를 나타낸다.

 

배열의 기능 

배열은 자신의 요소를 내부 정적 C 배열에 복사한다.

요소들은 항상 특정한 순서를 갖게된다.

따라서 배열은 일종의 정렬 컨테이너로 볼 수 있다.

배열은 임의 접근을 허용하기 때문에 요소의 위치를 알고 있다면 상수 시간 내에 접근할 수 있다.

 

만약 고정된 요소 수를 갖는 순서 컨테이너가 필요하다면 array를 사용하는 것이 좋다.

메모리가 가능한 스택에 할당되며, 재할당이 일어나지 않고 임의 접근이 가능하기 떄문이다.

 

배열의 기능 - 초기화 

기본 생성자는 빈 컨테이너를 생성하지 않는다.

이는 배열의 요소 수는 두번째 매개변수로 받은 수로 항상 유지되기 때문이다.

빈 컨테이너 처럼 만들고 싶다면 빈 초기화자 목록을 사용할 수 있다.

 

이렇게 사용하면 배열의 모든 요소를 0으로 초기화 할 수 있다.

초기화자 목록의 개수가 배열의 요소 최대 수보다 적다면 모자란 부분은 자동으로 0이된다.

초기화자 목록의 개수가 배열의 요소 최대 수보다 많으면 에러가 발생한다.

배열은 초기화자 목록을 위한 생성자나 할당 연산자가 없기 때문에 선언할 때만 사용가능하다.

그로 인해 초기값을 명시할 때 괄호를 사용할 수 없다.

단, 다른 컨테이너들은 사용가능하다.

 

array는 에러가 발생하고 vector는 에러가 발생하지 않는 것을 볼 수 있다.

 

배열의 기능 - swap과 이동 문맥

자신의 요소를 같은 데이터형을 갖는 컨테이너의 요소와 교환할 수 있다.

하지만 내부적으로 포인터만 교환할 수 없기 때문에 선형복잡도를 가지며 반복자와 참조자는 교환되지 않는다.

반복자와 참조자는 교환 후 다른 요소를 갖게 된 원래 컨테이너를 참고한다.

 

이동 문맥도 사용 가능하다. 

이동 문맥을 암묵적으로 제공한다.

 

배열의 기능 - 크기 

크기가 0인 배열도 선언할 수 있다.

이러한 경우 begin()과 end(), cbegin() 과 cend()와 역방향 반복자 모두 동일한 값을 반환한다.

그러나 front()와 back()의 반환값은 정의되지 않았다.

 

배열 연산 

배열 연산 - 생성, 복사와 소멸

array<> 클래스는 집합이기 때문에 이들 생성자는 암묵적으로 정의되어 있다.

 연산  효과 
 array<elem, n> arr  기본 생성자, 기본값으로 초기화된 요소를 갖는 배열을 만든다
 array<elem, n> arr(arr2)  복사 생성자. 같은 데이터형의 다른 배열을 복사한 배열을 만든다. 모든 요소 복사
 array<elem, n> arr= arr2  복사 생성자. 같은 데이터형의 다른 배열을 복사한 배열을 만든다. 모든 요소 복사
 array<elem, n> arr(rv)  이동 생성자, rv의 내용을 갖는 새로운 배열을 만든다, C++11 이후 지원한다.
 array<elem, n> arr = rv  이동 생성자, rv의 내용을 갖는 새로운 배열을 만든다, C++11 이후 지원한다.
 array<elem, n> arr = initlist  초기화자 목록 initlist 내의 요소로 초기화된 배열을 만든다.

 

 

배열 연산 - 수정하지 않는 연산

 연산  효과 
 arr.empty()  컨테이너가 비었는지 여부를 알려준다. size()==0과 같지만 더 빠를 수 있다
 arr.size()  현재 요소의 수를 반환
 arr.max_size()  최대 저장 가능한 요소의 수를 반환
 arr1 == arr2  arr1이 arr2와 같은지 반환, 각 요소에 대해 == 호출, 모든 요소가 같아야 한다
 arr1 != arr2  arr1이 arr2 와 다른지 반환, !(arr1==arr2)와 같다
 arr1 < arr2  arr1이 arr2보다 작은지 반환
 arr1 > arr2  arr1이 arr2보다 큰지 반환
 arr1 <= arr2  arr1이 arr2보다 작거나 같은지 반환
 arr1 >= arr2  arr1이 arr2보다 크거나 같은지 반환.

 

 

배열 연산 - 할당 

할당 연산자 이외에 각 요소에 새로운 값을 할당하는 방법은 fill() 뿐이다.

다른 배열에서 값을 교환하고 싶다면 swap()을 사용한다.

= 연산자와 swap()의 경우 두 배열은 데이터형과 배열의 크기가 같아야한다.

 연산  효과 
 arr1 = arr2  arr2의 모든 요소를 arr1에 할당
 arr = rv  rv의 모든 요소를 arr에 할당, C++11 이후 지원
 arr.fill(val)  배열 arr의 각 요소에 val 할당
 arr1.swap(arr2)  c1과 c2의 데이터를 교환
 swap(arr1, arr2)  c1과 c2의 데이터를 교환

 

배열에 대한 swap() 함수는 상수 복잡도를 보장하지 못한다.

이 표 내의 모든 연산은 요소 데이터형의 할당 연산자를 호출한다.

 

배열 연산 - 요소 접근 

배열의 모든 요소에 접근하기 위해선 범위 기반 for문이나 특정 연산 또는 반복자를 사용해야 한다.

투플 인터페이스가 제공되는 경우 특정요소에 접근할 때 get<>()을 사용할 수 있다.

 연산  효과 
 arr[idx]  인덱스 idx에 있는 요소를 반환 ( 범위 검사를 하지 않는다 )
 arr.at(idx)  인덱스 idx에 있는 요소를 반환 ( 범위 이외의 것이면 범위 오류 예외를 던진다 )
 arr.front()  첫 번째 요소 반환 ( 첫 번째 요소가 존재하는지 확인하지 않는다 )
 arr.back()  마지막 요소 반환 ( 마지막 요소가 존재하는지 확인하지 않는다 )

 

at() 함수를 사용했을 때 범위를 넘어가면 out_of_range 예외를 던진다.

at() 함수만 예외 검사를 하기 때문에 주의하고 사용해야 한다.

 

배열 연산 - 반복자 함수 

배열 반복자는 임의 접근 반복자이다.

따라서 원칙적으로 STL의 모든 알고리즘을 사용할 수 있다.

 연산  효과 
 c.begin()  첫 번째 요소에 대한 임의 접근 반복자 반환
 c.end()  마지막 요소 다음 위치에 대한 임의 접근 반복자 반환
 c.cbegin()  첫 번째 요소에 대한 임의 접근 상수 반복자 반환 ( C++11 이후 지원 )
 c.cend()  마지막 요소 다음 위치에 대한 임의 접근 상수 반복자 반환 ( C++11 이후 지원 )
 c.rbegin()  역방향 반복에서의 첫 번째 요소에 대한 역방향 반복자 반환
 c.rend()  역방향 반복에서의 마지막 요소 다음 위치에 대한 역방향 반복자 반환
 c.crbegin()  역방향 반복에서의 첫 번째 요소에 대한 역방향 상수 반복자 반환 ( C++11 이후 지원 )
 c.crend()  역방향 반복에서의 마지막 요소 다음 위치에 대한 역방향 상수 반복자 반환 ( C++11 이후 지원 )

 

 

array를 C배열로 사용하기 

C++표준 라이브러리는 array<>의 모든 요소들이 연속된 메모리 상에 존재하는 것을 보장한다.

따라서 &a[i] == &a[0] + i 가 성립한다.

그렇기에 array<>를 C언어에서의 배열처럼 사용해도 무방하다.

 

예외 처리 

배열은 논리 오류를 최소한으로만 검사한다.

표준에 따르면 at() 함수만 예외가 허용되었다.

따라서 사용자가 예외 처리를 해야한다.

 

투플 인터페이스 

배열은 투플 인터페이스를 제공하기 때문에 요소의 수를 얻을 때에는 tuple_size<>::value 표현식을, 특정 요소의 데이터형을 얻을 때에는 tuple_element<>::type을, 특정 요소로 접근할 때는 get<>()을 사용할 수 있다.

728x90