C++에서 일반적으로 크기가 정해지지 않은 배열을 사용하기 위해 vector<type>를 사용하고, 크기가 정해진 배열을 사용하기 위해 array<type, size>를 사용합니다. 그리고 vector와 array의 원소를 for문을 통해 접근할 때 다음과 같은 코드를 작성합니다.
vector<int8_t> vec;
int length = vec.size();
for (int i = 0; i < length; i++) {
vec[i] = i;
}
그리고 문득 vector의 인덱스 접근 방식과 일반 배열 []의 처리 성능이 얼마나 차이나는지 궁금하여 반복문으로 값을 할당하는 실험을 진행하였습니다.
시간 측정 도구는 제가 이전에 작성한 HourMeter 클래스 객체를 사용하여 진행하였습니다.
vector와 array 그리고 일반 배열[]을 크기 1,000,000 만큼 할당한 후 각 원소 i에 값 i를 할당하는 작업을 20번 반복하는 실험을 진행하였습니다.
이에 대한 소스코드는 아래와 같습니다.
void main() {
constexpr int N = 1'000'000;
constexpr int M = 20;
HourMeter hourMeter;
vector<int8_t> vec;
vec.resize(N);
array<int8_t, N> arr;
int8_t* arr2 = new int8_t[N];
try {
printf("vector - 인덱스 직접 접근 방식\n");
hourMeter.startMeasure();
for (int j = 0; j<M; j++)
{
int length = vec.size();
for (int i = 0; i < length; i++) {
vec[i] = i;
}
}
hourMeter.endMeasure();
printf("array - 인덱스 직접 접근 방식\n");
hourMeter.startMeasure();
for (int j = 0; j<M; j++)
{
int length = arr.size();
for (int i = 0; i < length; i++) {
arr[i] = i;
}
}
hourMeter.endMeasure();
printf("일반 배열 - 포인터 할당 후 접근 방식\n");
hourMeter.startMeasure();
for (int j = 0; j<M; j++)
{
int length = N;
for (int i = 0; i < length; i++) {
arr2[i] = i;
}
}
hourMeter.endMeasure();
}
catch (exception& ex) {
printf("EXCEPTION: %s\n", ex.what());
return;
}
delete[] arr2;
}
실험 결과는 아래와 같습니다.
vector의 인덱스 접근 방식이 3.95초로 가장 느렸으며, array 가 0.41초로 두 번째, 일반 배열[]이 0.04초로 가장 빠른 성능을 보였습니다. 특히, 일반 배열은 vector보다 약 100배 빠른 성능을 보여주었습니다.
vector와 array에는 data()라는 멤버함수가 있는데 이는 vector와 array가 실제 데이터에 대한 메모리 주소를 반환하는 함수입니다. 저는 이를 포인터로 받아서 일반 배열처럼 처리하면 성능이 어떨지 궁금하여 마찬가지로 실험을 진행해보았습니다.
이에 대한 소스코드는 아래와 같습니다.
void main() {
constexpr int N = 1'000'000;
constexpr int M = 20;
HourMeter hourMeter;
vector<int8_t> vec;
vec.resize(N);
array<int8_t, N> arr;
int8_t* arr2 = new int8_t[N];
try {
printf("vector - 인덱스 직접 접근 방식\n");
hourMeter.startMeasure();
for (int j = 0; j<M; j++)
{
int length = vec.size();
for (int i = 0; i < length; i++) {
vec[i] = i;
}
}
hourMeter.endMeasure();
printf("vector - 포인터 할당 후 접근 방식\n");
hourMeter.startMeasure();
for (int j = 0; j<M; j++)
{
int length = vec.size();
int8_t* temp_arr = vec.data();
for (int i = 0; i < length; i++) {
temp_arr[i] = i;
}
}
hourMeter.endMeasure();
printf("array - 인덱스 직접 접근 방식\n");
hourMeter.startMeasure();
for (int j = 0; j<M; j++)
{
int length = arr.size();
for (int i = 0; i < length; i++) {
arr[i] = i;
}
}
hourMeter.endMeasure();
printf("array - 포인터 할당 후 접근 방식\n");
hourMeter.startMeasure();
for (int j = 0; j<M; j++)
{
int length = arr.size();
int8_t* temp_arr = arr.data();
for (int i = 0; i < length; i++) {
temp_arr[i] = i;
}
}
hourMeter.endMeasure();
printf("일반 배열 - 포인터 할당 후 접근 방식\n");
hourMeter.startMeasure();
for (int j = 0; j<M; j++)
{
int length = N;
for (int i = 0; i < length; i++) {
arr2[i] = i;
}
}
hourMeter.endMeasure();
}
catch (exception& ex) {
printf("EXCEPTION: %s\n", ex.what());
return;
}
delete[] arr2;
}
실험 결과는 아래와 같습니다.
실험 결과, vector 또는 array를 data() 멤버 함수를 통해 메모리 주소를 포인터로 받은 후 일반 배열처럼 사용하면 성능 상 일반 배열과 차이가 없었습니다.
결론적으로, 성능을 중요시 여긴다면 vector 또는 array를 data로 접근하여 사용하는 것도 고려해볼 만 합니다.
'컴퓨터 공학 > C++' 카테고리의 다른 글
[C++] vector 컨테이너 반복문 종류별 성능 (0) | 2019.11.14 |
---|---|
[C++] 구조체 정렬 크기 조절하기 (0) | 2019.11.14 |
[C++11] 초간단 시간 측정 클래스 (0) | 2019.11.14 |
C++ 함수 내 람다 함수를 통해 코드 정리 (0) | 2019.11.14 |
const_cast 사용 예시 (0) | 2019.11.14 |