reference: "전문가를 위한 C++" / 마크 그레고리
std::array는 메모리를 자동으로 할당하고 해제한다. std::array는 원소의 타입과 배열 크기를 매개변수로 사용하는 클래스 템플릿이다.
정적 배열과 유사한 동작을 하는 고정 크기 배열 클래스이며, 배열의 크기는 컴파일 시간에 결정된다. std::array는 배열의 데이터들은 힙이 아닌 스택 메모리에 할당된다.
std::array<int, 10> arr1;
arr1[0] = 1;
std::array<int, 4> arr2 = {1, 2, 3, 4};
std::array는 C 스타일 배열과 똑같은 방식으로 배열 원소에 접근할 수 있는 []
연산자를 제공한다. []
연산자에 접근하고자 하는 배열 원소 인덱스(index)를 지정할 경우, 빠른 동작을 위해 전달된 인덱스 값이 배열의 크기보다 작은지 검사하지는 않는다.
대신 std::array의 at(index) 형식의 함수도 함께 제공하며, 이 함수는 인자로 전달된 index 값이 유효하지 않으면 std::out_of_range 예외(exception)를 발생시킨다. ([]
연산자보다는 조금 느린 편)
std::array<int, 4> arr3 = {1, 2, 3, 4};
try{
std::cout << arr3.at(3) << std::endl; // no error
std::cout << arr3.at(4) << std::endl; // std::out_of_range 예외 발생
}
catch (const std::out_of_range &ex) {
std::cerr << ex.what() << std::endl;
}
std::array 객체를 다른 함수에 전달하는 방식은 기본 데이터 타입을 전달하는 것과 유사하다. 값 또는 참조(reference)로 전달할 수 있고, const를 함께 사용할 수도 있다. C 스타일 배열을 함수에 전달할 때처럼 포인터 연산을 사용한다거나 참조(&) 또는 역참조(*) 연산을 하지 않아도 된다. 그러므로 다차원 배열을 전달하는 경우에도 std::array를 사용하는 것이 가독성이 훨씬 좋다.
void print(std::array<int, 5> arr){
for(auto ele : arr)
std::cout << ele << ', ';
}
std::arr<int, 5> arr = {1, 2, 3, 4, 5};
print(arr);
위 print() 함수는 매개변수 데이터 타입에 전달받을 배열 크기가 고정되어 있기에 다른 크기의 배열을 전달할 수 없다. 다양한 크기의 std::array 객체에 동작하는 범용적인 배열 출력함수를 만들고자 한다면, 함수를 템플릿으로 선언하고, 배열 크기를 템플릿 메개변수로 전달하면 된다.
template<size_t N> void print(const std::array<int, N> &arr);
std::array 객체를 전달할 경우, 기본적으로 새로운 배열(별도의 주소)에 모든 원소가 복사된다. 즉, 자동으로 '깊은 복사'가 동작한다. 만약 이러한 동작을 피하고 싶다면 참조 또는 const 참조를 사용할 수 있다.
// 참조에 의한 호출로 복사에 대한 오버헤드를 줄인다.
void print(const std::array<int, 5>& arr){
for(auto ele : arr)
std::cout << ele << ', ';
}
std::arr<int, 5> arr = {1, 2, 3, 4, 5};
print(arr);
배열의 원소를 차례대로 접근하는 연산에서 std::array는 (1) 반복자(iterator)와 (2) 범위 기반 for문을 이용하여 원소에 차례대로 접근할 수 있다.
// (2) 범위 기반 for문
for(auto ele : arr)
std::cout << ele << ', ';
범위 기반 for문은 begin() 위치부터 시작하여 증가 연산자를 통해 차례대로 원소를 이동하다가 end() 위치에 도달하면 종료된다.
(반복자는 array, vector, map, set, list처럼 반복 가능한 모든 STL 컨테이너에 대해 사용할 수 있다.)
iterator 활용 for문
// (1) 반복자를 활용한 for문
for(auto it = arr.begin(); it != arr.end(); it++){
auto ele = (*it);
std::cout << ele << ', ';
}
std::array는 깊은 비교를 위한 관계 연산자와 깊은 복사를 위한 복사 할당 연산자도 지원한다.
std::array에 저장되는 데이터 타입에서 크기 비교(관계 연산자: <, >, <=, >=, ==, !=)를 지원할 경우, 이들 관계 연산자를 이용하여 두 std::array 배열을 비교하는 용도로 사용할 수도 있다.
C 스타일 배열에 대해서도 관계 연산자를 사용할 수 있지만, 배열 원소 값을 비교하는 것이 아닌 포인터 주소를 비교한다. 즉 깊은 비교가 아닌 얕은 비교이다.
std::array의 경우 값으로 비교할 수 있도록 함수가 재정의되어있다. 객체의 값이 동일한 지 판단하는 '==' 연산자가 재정의되어있는데, 배열의 길이와 그 요소들이 모두 같은 지 판단한다. 깊은 비교가 이루어진다.
할당에 대해서도 C 스타일 배열은 메모리를 새로 생성하여 값을 복사(깊은 복사)하지 않으며, 단순히 같은 배열 데이터를 가리키는 새로운 포인터를 생성한다(얕은 복사).
cf) std::array에 대해 관계 연산자를 사용할 경우, 두 배열의 크기가 같아야 합니다. 이는 std::array로 생성한 배열 객체의 경우, 배열의 크기가 데이터 타입 일부로 동작하기 때문이다. 즉, 크기가 다른 배열은 서로 다른 타입으로 인식되므로 비교할 수 없다.
std::array는 배열의 데이터들은 힙이 아닌 스택 메모리에 할당된다.
source: https://hackingcpp.com/cpp/std/sequence_containers.html