std::array 소개 본문
std::array
이전 포스트들에서 고정 배열(fixed array)과 동적 배열(dynamic array)을 배웠다.
두 가지 배열 모두 C++에 내장되어 있지만,
포인터로 형 변환되었을 시 배열 길이 정보가 손실되고,
동적 배열은 지저분한 할당 해제 문제가 있다.
이러한 문제를 해결하기 위해 C++ 표준 라이브러리는 배열 관리를 쉽게 해주는 std::array와 std::vector가 있다.
An introduction to std::array in C++11
C++ 11에서 소개된 std::array는 함수에 전달할 때 포인터로 형 변환되지 않는 고정 길이 배열이다.
std::array는 <array>헤더의 std namespace 내부에 정의되어 있다.
array를 선언할 때
std::array 변수 선언은 쉽다.
#include <array>
std::array<int,5>myArray; // declare an integer array with length 5
둘 다 const 붙일 수 있고, using namespace std 쓰면 std도 생략할 수 있다.
array 같은 일반적인 단어는 변수명으로 쓰면 충돌이 생길 수 있다.
std::array는 참 편한데
단점이 고정 배열 선언처럼 array의 길이는 컴파일 타임에 설정해야 한다.
그냥 내장된 고정 array는
이렇게 해도 알아서 컴파일러가 다섯개라고 해줬는데..
std::array는 안먹힌다.
그 외에 array로 할 수 있는 거는 다 된다고 보면 된다.
std::array는 초기화 리스트(initializer list) 또는 유니폼 초기화(uniform initialization)를 사용해서 초기화할 수 있다.
std::array<int, 5> myArray = {9, 7, 5, 3, 1}; //initialization list
std::array<int, 5> myArray2 {9, 7, 5, 3, 1}; //uniform initialization
또한 초기화 리스트를 사용해서 배열에 값을 할당할 수 있다.
std::array<int, 5> myArray;
myArray = {0, 1, 2, 3, 4}; // okay
myArray = {9, 8, 7}; // okay, elements 3 and 4 are set to 0!
myArray = {0, 1, 2, 3, 4, 5}; // now allowed, too many elements in initializer list!
이런 식으로 대입할 수 있는데 element 개수가 적어준 것보다 많으면 오류 난다.
하지만 적을 때는 상관없다.
나머지는 0으로 채워준다.
cout도 당연히 같은 방식으로 작동한다.
일반 배열처럼 첨자 연산자[ ] 를 사용해서 배열의 요소 값에 접근할 수 있다.
std::array는 찍을 수 있는 방법이 한 가지 더 있다.
. 을 찍고 at을 쓰고 (0) 하면 위와 똑같이 작동한다.
대괄호[ ] 아니고 괄호 ( )인 거 주의하자!
at은 멤버 함수 이름이다. 그래서 뒤에 괄호가 와야 한다.
일반 배열 array에서 사용하던 대괄호[ ] 방식하고 .at( )의 차이점은 무엇일까?
위에 대괄호는 10이
여기가 5니까
이 자리에 0,1,2,3,4 까지만 들어갈 수 있는데
이게 넘는지 안 넘는지 유효 범위 검사도 안 하고 바로 무조건 access 해버린다.
잘못된 index가 들어가면 나쁜 일이 발생한다.
그런데 .at을 사용하면 미리 한번 체크를 해보고 문제가 생기면 예외처리를 발동시킨다.
일단 여기서는 중간에 유효 범위 검사를 하니까 아무래도 속도가 조금 더 느리다.
퍼포먼스가 아주 중요한 프로그램을 만들 때는 위에 거를 쓰는 게 낫다.
Size
그리고 몇 가지 편리한 기능들이 있다.
size() 함수를 사용해서 배열의 길이를 알 수 있다.
함수 파라미터로 보낼 때에도 원래 성질이 그대로 유지가 된다.
std::array는 함수에 전달될 때 포인터로 형 변환되지 않기 때문에
size() 함수는 함수 내에서 호출하더라도 정상적으로 작동한다.
여기서 주의해야 할 점이 두 가지 있다.
첫 번째,
표준 라이브러리에서는 "size"라는 용어는 배열 길이를 의미하므로
sizeof() 연산자의 결과와 혼동하면 안 된다.
(sizeof() 결과: 배열 요소 자료형의 크기 * 배열 길이)
두 번째,
일반 변수도 파라미터로 집어넣으면 한번 복사가 된다고 말씀드린 적 있다. array도 복사가 된다.
그래서 array가 많이 클 경우에는 복사하는데 시간이 걸린다.
그럴 경우에는 포인터로 보내는 방법도 있고 레퍼런스를 쓰는 방법도 있는데
위 예제에서는 성능상의 이유로 레퍼런스를 쓰면 참 편하다.
std::array가 함수로 전달될 때 컴파일러가 배열의 복사본을 만드는 것을 방지하기 위해서다.
std::array는 항상 참조로 전달하자.
그리고 my_arr가 함수 안에서 변하지 않기를 원한다면 const로 수정을 막아버릴 수 있다.
그래서 array나 vector 같은 표준 라이브러리 사용할 때는
이렇게 함수 파라미터로 넣을 때
레퍼런스를 쓸 것인지, 포인터를 쓸 것인지, const를 붙일 건지 아니면 그냥 넣을 것인지 잘 생각해보고 넣어야 한다.
std::array의 길이는 항상 알려져 있기 때문에 for-each 루프로 사용할 수 있다.
이 때도 마찬가지로 레퍼런스를 달아줄 수 있다.
sorting
sort(정렬)가 알고리즘에 들어있다.
<algorithm> 헤더에 있는 std::sort를 사용해서 std::array를 정렬할 수 있다.
.begin , .end는 처음부터 끝까지 sorting 하려고 써준 거다.
물론 원하시다면 sorting을 중간까지만 할 수도 있다.
이전 포스팅에서 selection sort 한번 직접 구현해보시라고 말씀드린 적 있다.
배열과 선택 정렬 Selection Sort
배열과 선택 정렬 Selection Sort 맛있는 음식이 여러가지 있을 때 어느 것을 먼저 먹을지 순서를 정하기도 하고, 사람이 여러명 있을 때 키 순서대로 세워보기도 한다. 이렇게 순서를 맞춰주는
hyoniidaaa.tistory.com
실전에서는 직접 구현한 것을 사용할 일이 많지는 않지만, 한 번씩 해보면 공부에 도움이 많이 된다.
실제로는 이런식으로 아주 편리하게 사용할 수 있는 라이브러리들이 많다.
역순 정렬은 어떻게 하면 될까?
std::array에 대해서 알아보았다.
std::array는 내장된 고정 array와 용법은 거의 비슷하다.
그러나 내장된 고정 배열보다 메모리를 더 사용하지 않으며,
함수로 전달 시 포인터로 형 변환되지 않는 장점이 있다.
단점은 선언할 때 배열 길이를 명시적으로 지정해야 한다는 것이 있다.
std::array는 여러 가지 면에서 편리하게 사용할 수 있다.
'💘 C++ > 행렬, 문자열, 포인터, 참조' 카테고리의 다른 글
std::vector 소개 (0) | 2022.07.23 |
---|---|
이중 포인터와 동적 다차원 배열 (Pointers to pointers and dynamic multidimensional arrays) (0) | 2022.07.22 |
보이드 포인터 (void pointer) (0) | 2022.07.21 |
For-each 반복문 (ranged-based for statement) in C++11 (2) | 2022.07.20 |
포인터와 참조의 멤버 선택 Member selection with pointers and references (0) | 2022.07.20 |