광고


[TR1] array TR1/C++11/C++14/C++17




0. 들어가기에 앞서...

어느 정도 연식이 있는 개발자라면, 누구나 한번 직접 만들어 봤음직한 array container가 TR1에서 릴리즈 되었다.

STL container라면 갖추어야 할 기본 구성물과 핵심 자료구조로는 배열을 사용하고 있겠지만,
그래도 표준이지 않나?

직접 만든 것 보다 남들이 모두 사용할 수 있는 표준이라는 점에 새삼 반가웠던 건 사실이고,
릴리즈 된 지 몇년 만에 글을 포스트하는 게으름에 반성한다.


1. std::array

std::array의 MSDN 링크 페이지를 보면, 자세히 나와 있다.
(STL container라면 응당 갖추어야 할 요소를 모두 포함하고 있다고 보면 된다)

std::array를 사용하기 위해선 <array> 헤더 포함이 필요하며, 아래와 같이 선언할 수 있다.

template<class Ty, std::size_t N>
class array;

일반 배열처럼 초기화 목록을 사용하여 초기화할 수 있다.

예제를 통해 기본적인 기능에 대해 살펴보자.

  1. #include <array>
  2. #include <iostream>
  3.  
  4. using namespace std;
  5.  
  6. // int 타입 4개짜리 array
  7. typedef array<int4> MyArray;
  8.  
  9. int main()
  10. {
  11.     // C 배열처럼 초기화 목록을 통해 초기화가 가능하다
  12.     MyArray c0 = {0123};
  13.  
  14.     // 여느 STL container처럼 iterator를 통한 순회
  15.     for (auto it = c0.begin(); it != c0.end(); ++it)
  16.     {
  17.         cout << " " << *it;
  18.     }
  19.     cout << endl;
  20.  
  21.     // array::data() 함수는 첫번째 원소의 주소를 반환한다.
  22.     MyArray::pointer ptr = c0.data();
  23.     cout << " " << *ptr << endl;
  24.  
  25.     // 당연하게도 operator []을 지원하며,
  26.     cout << "2nd Number is " << c0[1] << endl;
  27.  
  28.     // vector의 at()도 지원한다.
  29.     cout << "3rd Number is " << c0.at[2] << endl;    
  30.  
  31.     return (0);
  32. }

배열이라는 개념 자체가 낯설지 않고, 워낙 기본적인 STL container의 형태에 머물러 있기에
특별히 어려울 것도 없어 뭐 기능에 대한 더 자세한 설명은 생략하겠다.


2. size 0 array?

다시 한번 array 클래스의 선언을 살펴보면, Ty 타입의 원소를 N 개만큼 선언하도록 되어 있다.

template<class Ty, std::size_t N>
class array;

그리고, array 클래스는 아래와 같이 Ty 데이터들을 C 배열로 관리하고 있다.

  1. template<class _Ty, size_t _Size>
  2. class array
  3. {
  4.     // ...
  5.  
  6. private:
  7.     _Ty _Elems[_Size == 0 ? 1 : _Size];
  8. };

즉, 배열의 크기로 0을 줄 수 없으므로, 위와 같이 _Size가 0으로 템플릿이 선언되면,
내부에서 크기가 1개인 배열로 설정을 하는 것이다.

하지만, _Size가 0으로 템플릿이 추상화될 경우 해당 array는 문법적으로 문제가 없는 
완전히 비어 있는 array로 동작하도록 부분 특수화 버전으로 생성된다.

  1. template<class _Ty>
  2. class array<_Ty, 0>
  3. {
  4.     // ...
  5.     // 데이터를 셋팅할 수 없고, empty는 늘 true를 반환한다.
  6.  
  7. private:
  8.     Ty _Elems[1];
  9. };

음...그냥 array[0]과 같은 실수를 하지 말라고 만들어 놓은 건가?
만약, 그렇다면 static_assert로 컴파일 타임에 걸러낼 수 있도록 하는 게 더 좋지 않았을까?

왜 굳이 이걸 이렇게 해 놨는지 아직은 그 용도를 확실히 모르겠다.


3. 배열 vs std::array

위 array 소개에 나온 예제에 일부러 몇몇 기능에 대해 소개를 하지 않았었는데,
이는 기존 C 배열에 비해 std::array가 조금이라도 나은 점을 보여주고 싶어서였다.

어떠한 점들이 더 나은지, 아래 예제를 통해 살펴보자.

  1. #include <iostream>
  2. #include <vector>
  3. #include <array>
  4.  
  5. using namespace std;
  6.  
  7. struct FolderInfo
  8. {
  9.     int idx;
  10.     vector<int> fileIdxs;
  11. };
  12.  
  13. #define MAX_FOLDER_CNT          (100)
  14.  
  15. typedef array<FolderInfo, MAX_FOLDER_CNT> FolderArray;
  16.  
  17. int _tmain(int argc, _TCHAR* argv[])
  18. {
  19.     FolderArray fa;
  20.  
  21.     for (int i = 0; i < MAX_FOLDER_CNT; i++)
  22.     {  
  23.         fa[i].idx = i + 1;
  24.         for (int j = 1; j <= 5; j++)
  25.         {
  26.             fa[i].fileIdxs.push_back((+ 1) * j);
  27.         }
  28.     }
  29.  
  30.     /- 할 수 있으면 random access를 직접하는 것보다,
  31.        이러한 함수를 통한 접근이 실수를 조금이라도 줄여줄 수 있다 *-        
  32.  
  33.     // fa[0] 보다는 front
  34.     const FolderInfo& first = fa.front();
  35.  
  36.     // fa[MAX_FOLDER_CNT - 1]보다 back은 특히나 실수로부터 안전하다.
  37.     // 특히 위와 같이 정의된 상수를 쓰는 게 아니라,
  38.     // 숫자로 직접 배열 크기를 지정한 코드에서는 실수할 확률이 더욱 높다. (ex. Array[99])
  39.     const FolderInfo& last = fa.back();
  40.  
  41.     FolderArray fb;
  42.     // memcpy 따윈 이제 안녕~
  43.     // 직접 메모리를 제어하는 함수는 가급적 안 쓰는게 좋다
  44.     fb = fa;
  45.  
  46.     FolderArray fc;
  47.     // C 배열도 알고리즈 함수를 쓰면 어찌 되긴 하나,
  48.     // 멤버 함수가 보통의 경우 알고리즘 함수보다 더 낫다.
  49.     fc.swap(fb);
  50.  
  51.     // C 배열이었다면, for loop 돌면서 해야할 것인데, 이게 훨 직관적이고 편하다
  52.     array<FolderInfo*, MAX_FOLDER_CNT> fpa;
  53.     fpa.fill(nullptr);
  54.  
  55.     return 0;
  56. }

위에서 기능별로 내세운 기능별 이점 외, 하나의 이점을 더 설명하고 싶다.

프로젝트에서 STL container를 비중있게 사용하는 편이라면 다른 코드의 흐름이나 일관된 코드 스타일을 위해서라도,
C 배열보다는 array를 쓰는 것이 조금 더 낫지 않을까 생각한다.


덧글

댓글 입력 영역