예...늦은 감이 없지 않아 있습니다만,
C++11에서 새로 추가된 컨테이너, std::array에 대해서 포스팅 해보려고 합니다.
기존 C-스타일 배열과 비교를 해 보겠습니다.
1. 배열생성
1부터 10까지 들어있는 배열을 생성하겠습니다.
#include <iostream>
#include <array>
#include <algorithm>
using namespace std;
...와 같은 헤더 혹은 uns는 생략하겠습니다. 이 모든 헤더파일이 import std.core; 하나면 끝
// [코드 1: 배열 생성]
// C++11이상에서 동작합니다.
int main() {
int carray[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::array<int, 10> stdarray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
}
하지만 우린 여기서 더 줄일 수 있죠.
// C에서는 대입연산자 넣어줘야 합니다!!
int carray[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// C++14까지는 <int, 10> 넣어줘야 합니다!!
array stdarray{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
저번에 deduction guide에 관해 글을 하나 썼습니다만...
array을 array로만 써도 되는 기적을 만들어줬죠.
배열 생성 자체는 std::array가 더 쉬워보입니다. []도 필요없고, 타입도 적을 필요가 없으니까요.
(단, 모든 원소의 자료형이 일치해야 합니다. 그렇지 않으면 타입 추론시 오류가 납니다.)
2. 부분 초기화
배열의 3, 7번째 요소만 9로 초기화 해 봅시다.
// [코드 2: 부분 초기화]
int main() {
int carray[10]{0, 0, 9, 0, 0, 0, 9};
array<int, 10> stdarr{0, 0, 9, 0, 0, 0, 9};
}
초기화라고 언급하였으니 배열을 만든 후 값을 대입하는 경우는 생각하지 않았습니다.
C-Array의 경우 배열 크기만 써주어도 편하게 작성할 수 있는 반면,
std::array는 하나하나 원소를 다 써야 합니다. 뒤에 0만 있다면 그부분은 생략해도 되지만,
array가 아니라 array<int, 10>이라고 명시해야 합니다.
참고로 C++이 아니라 C언어에서는 아래와 같은 초기화도 지원합니다.
int carray[10] = { [2] = 9, [6] = 9 };
3. 배열의 순회
전체 배열의 요소를 순회해볼까요?
// [코드 3: 배열의 순회]
// C++17 이상에서 동작합니다. (<int, 10>을 명시할 경우 C++11부터)
int main() {
int carray[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
array stdarr{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// carray를 stdarr로 바꿔도 잘 작동한다.
for (int n : carray)
cout << n << endl;
// stdarr을 carray로 바꾸면 성공적으로 오류가 난다.
copy(stdarr.cbegin(), stdarr.cend(), ostream_iterator<int>(cout, "\n"));
}
마지막의 copy를 굳이 carray에 쓰고 싶다면
copy(begin(X), end(X), ostream_iterator<int>(cout, "\n"));
X자리에 carray를 넣으시면 됩니다. 물론 기존 STL, array도 begin()을 사용할 수 있습니다.
vector v; 라면 v.begin() == begin(v)와 같은데 이는 일관성을 위한 것입니다.
int arr[3]; arr.begin()은 안되지만 begin(arr)은 가능합니다.
4. 잘못된 접근
인덱스를 벗어나 봅시다.
// [코드 4: 잘못된 접근]
// C++17 이상에서 동작합니다. (<int, 10>을 명시할 경우 C++11부터)
int main() try {
int carray[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
array<int, 10> stdarr{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
[[maybe_unused]] auto n = carray[11];
n = stdarr[11];
n = stdarr.at(11);
}
catch (const out_of_range &exception) {
cout << "Exception caugted: " << exception.what() << endl;
}
main()을 자세히 보세요. 뭔가 이상하지 않습니까?
int main() try { 라니?
이건 function-try-block이라고 하여 try-catch문 자체가 함수 몸체를 이룹니다.
각설하고, 프로그램의 흐름을 보면 n = stdarr.at(11)에서 예외가 발생합니다.
자기 자신의 크기를 알기 때문에 11번째 요소는 없다는 것을 알고 오류를 뱉은 것이지요.
역시 모던 C++입니다.
C++11의 std::array는 C언어의 배열보다 안전합니다. 또한 사용하기도 편리하고, STL답게 기능도 많습니다.
혹시라도 지금 C언어의 배열을 쓰신다면, 다시 한번 생각해 보시기 바랍니다.
M$가 비주얼스튜디오에 괜히 scanf_s를 넣은 것이 아닙니다. 버퍼 오버플로우, 굉장히 심각한 문제인 것 아시죠? 그걸 막아주는게 STL의 래퍼 클래스입니다.
천천히 적응해 보세요. 정말 도저히 std::array가 나하고는 안맞다,
그때 바꾸셔도 충분 합니다. 우선 array가 있다는건 알아야 하나까요.
'C++' 카테고리의 다른 글
나만의 C++ 프로그래밍 가이드 (0) | 2022.10.01 |
---|---|
[C++17] 템플릿 인자를 생략한다? Deduction Guide (0) | 2020.03.21 |
[C++11] 템플릿으로 배열을 함수에 넘기기 (0) | 2020.03.21 |
[C++20] printf() 쓰지 마세요! std::format() (2) | 2020.03.21 |
C++17 주요 기능 정리 (1) - 유용한 기능 편 (0) | 2020.03.21 |