3 분 소요

개요

기존의 vector는 C스타일의 배열과 호환성이 좋았으나, 요소 추가/삭제등이 필요하여 동적 메모리를 사용하다 보니, 메모리 할당시 힙을 사용합니다. 이 때문에 아무래도 메모리 할당 측면에서는 스택에 할당되는 C스타일의 배열보다 성능이 떨어졌습니다.

C++11 부터는 array가 추가되어 기존 C스타일의 배열처럼 연속된 메모리를 사용하는 컨테이너를 제공합니다. C스타일 배열처럼 컴파일 타임에 크기가 결정되어 스택에 할당되므로, 힙에 할당되는 vector 보다 성능이 좋습니다.

항목 설명 C스타일 배열 array vector
연속된 메모리 모두 연속된 메모리를 사용합니다. O O O
동적 메모리 할당 C스타일 배열과 array는 컴타일 타임에 크기가 결정되어 스택에 할당됩니다. X X O
요소 추가/삭제 C스타일 배열과 array는 요소를 추가/삭제할 수 없습니다. X X O
요소 접근 [] 인덱스 범위 검사를 하지 않습니다. O O O
요소 접근 at() 인덱스 범위 검사를 합니다. X O O
이터레이터 array와 vector는 순방향 및 역방향 탐색을 지원합니다. X O O
배열 주소 데이터의 첫번째 요소의 주소를 구할 수 있습니다. arr 또는 arr[0] arr.data() &v[0]
포인터로의 암시적 변환 C스타일 배열은 int* p = arr; 와 같이 포인터로 암시적 변환 됩니다.
오버로딩된 함수 결정 규칙에 따라 함수 인자로 C스타일 배열 사용시 포인터로 취급됩니다.
O X X
중괄호 초기화를 통한 요소 갯수 유추 배열은 초기화 요소의 갯수로 C스타일 배열의 요소 갯수를 유추하지만, array는 명시적으로 지정해야 합니다. O X O
중괄호 초기화를 통한 자동 제로 초기화 요소의 갯수보다 적게 초기화하면 나머지 요소는 0으로 초기화 됩니다. O O O
속도 C스타일 배열과 array가 스택에 할당되기 때문에, 힙에 할당되는 vector보다 빠릅니다. 1 2 3
대입 C스타일 배열은 대입을 지원하지 않으며, array는 요소의 갯수가 같으면 대입됩니다. X O O
1
2
3
4
5
6
7
8
9
10
11
12
std::array<int, 3> a{1, 2, 3};
std::array<int, 3> b{4, 5}; 
std::array<int, 2> c{4, 5};   

// int* ptr = a; // (X) 컴파일 오류. array는 포인터로 암시적 변환이 되지 않습니다.
int* ptr = a.data(); // data를 이용하면 포인터로 변환됩니다.  

EXPECT_TRUE(b[0] == 4 && b[1] == 5 && b[2] == 0); // 요소의 갯수보다 적게 초기화하면 나머지 요소는 0으로 초기화 됩니다.

// c = a; // (X) 컴파일 오류. 요소의 갯수가 다르면 컴파일 오류가 발생합니다.
b = a; // 요소의 갯수가 같으면 대입이 가능합니다.
EXPECT_TRUE(b[0] == 1 && b[1] == 2 && b[2] == 3);

array 멤버 함수

항목 내용
at() (C++11~) (작성중)
front() (C++11~) (작성중)
back() (C++11~) (작성중)
data() (C++11~) 컨테이너가 관리하는 메모리 블록을 리턴합니다.
begin(), end() (C++11~) (작성중)
cbegin(), cend() (C++11~) (작성중)
rbegin(), rend() (C++11~) (작성중)
crbegin(), crend() (C++11~) (작성중)
empty() (C++11~) (작성중)
size() (C++11~) (작성중)
max_size() (C++11~) (작성중)
fill() (C++11~) (작성중)
swap() (C++11~) (작성중)
== (C++11~)
!= (C++11~C++20)
(작성중)
<, <=, >, >= (C++11~C++20)
<=> (C++20~)
(작성중)
to_array() (C++20~) 기존 C스타일 배열로부터 array를 생성합니다.

배열, array, vector 속도 비교

다음은 C스타일 배열, array, vector의 생성/소멸과 접근 속도를 테스트한 예입니다. 시간 측정을 위해 chrono 라이브러리를 사용했습니다.

  1. 십만개의 요소를 십만번 생성/소멸했고,
  2. 십만개의 요소에 접근하여 값을 대입합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// 생성/소멸 테스트
void CStyleArrayConstruct() {
    for(int i{0}; i < 100000; ++i) {
        int arr[100000];
    }        
}
void STLArrayConstruct() {
    for(int i{0}; i < 100000; ++i) {
        std::array<int, 100000> arr;
    }        
}
void STLVectorConstruct() {
    for(int i{0}; i < 100000; ++i) {
        std::vector<int> arr(100000);
    }        
}      
// 접근 테스트
void CStyleArrayAccess() {
    int arr[100000];

    for(int i{0}; i < 100000; ++i) {
        arr[i] = i;
    }        
}
void STLArrayAccess() {
    std::array<int, 100000> arr;

    for(int i{0}; i < 100000; ++i) {
        arr[i] = i;
    }        
}
    void STLVectorAccess() {
    std::vector<int> arr(100000);

    for(int i{0}; i < 100000; ++i) {
        arr[i] = i;
    }        
}  

template<typename Func>
std::chrono::microseconds Measure(Func f) {
    std::chrono::system_clock::time_point start{std::chrono::system_clock::now()};    

    f();

    std::chrono::system_clock::time_point end{std::chrono::system_clock::now()};
    std::chrono::microseconds val{std::chrono::duration_cast<std::chrono::microseconds>(end - start)};

    return val;
}

// 생성/소멸 테스트
std::cout << "CStyleArray : " << Measure(CStyleArrayConstruct).count() << std::endl;
std::cout << "STLArray : " << Measure(STLArrayConstruct).count() << std::endl;
std::cout << "STLVector : " << Measure(STLVectorConstruct).count() << std::endl;

// 접근 테스트
std::cout << "CStyleArray : " << Measure(CStyleArrayAccess).count() << std::endl;
std::cout << "STLArray : " << Measure(STLArrayAccess).count() << std::endl;
std::cout << "STLVector : " << Measure(STLVectorAccess).count() << std::endl;

실행 결과는 다음과 같습니다. array가 생성/소멸이 C스타일 배열 보다 빠른게 좀 의외이긴 합니다.

1
2
3
4
5
6
7
CStyleArray : 660
STLArray : 228 // C스타일 배열보다 빠릅니다.
STLVector : 18612352 // 동적 할당을 하다보니 느립니다.

CStyleArray : 209
STLArray : 404 // operator[]을 이용하다 보니 C스타일 배열보다는 느립니다.
STLVector : 487 // operator[]을 이용하다 보니 C스타일 배열보다는 느립니다.

태그:

카테고리:

업데이트:

댓글남기기