C++/게임 개발자를 위한 C++ 문법

Array와 Vector의 차이점과 사용법

iiblueblue 2024. 12. 23. 11:40
⊙ Array와 Vector의 차이점을 알아보자.
⊙ Array의 선언, 활용할 수 있는 함수에 대해 알아보자.
⊙ Vector의 선언, 활용할 수 있는 함수에 대해 알아보자.

 

Array와 Vector의 차이점

Array와 Vector 모두 여러 개의 데이터를 연속된 메모리 블록에 저장하는 자료구조라는 점은 동일하다. 하지만 이 둘을 구분하여 사용하고 있다는 것은 둘 사이에는 명백한 차이가 존재한다는 뜻이다.

정적 크기 VS 동적크기

Array는 크기가 고정적이다. 선언할 때 크기를 반드시 지정해야 하며 실행 중에 중간에 크기를 변경할 수는 없다. 이는 선언시 메모리가 고정되기 때문이다.

하지만 Vector은 크기가 동적으로 변한다. 크기를 정하지 않고 요소를 추가하거나 제거할 수 있으며 크기가 자동으로 조절된다. 메모리 재할당이 용이하다.

 

기능(타입)

Array는 기본적인 자료구조이기 때문에 추가적인 기능을 가지고 있지 않다. 만약 크기, 정렬, 삽입 등의 작업을 수행하려면 직접 구현해야 한다.

반면 Vector은 C++ 표준 라이브러리(STL) 컨테이너이기 때문에 다양한 메서드와 연산자를 제공하고 있다. 크기, 삽입, 삭제 등 자주 사용하는 기능들은 미리 구현되어 있기 때문에 직접 구현하지 않아도 쉽게 사용할 수 있다.

 

메모리 관리

Array는 메모리를 사용자가 직접 관리해야 한다. 크기 초과에 대한 보호 기능이 없으므로, 크기 이상의 요소에 접근 시 예외가 발생하지 않고 비정상으로 동작할 수 있다.

반면 Vector은 STL이 메모리를 자동으로 관리하고 있다. 크기가 초과될 경우, 내부적으로 새로운 메모리 공간을 할당하여 기존 데이터를 복사한다. 경계 초과 접근시 조용히 있는 Array와 다르게 Vector은 std::out_of_range 예외가 발생할 수 있습니다.

 

성능

Vector의 다양한 기능들에 혹할 수도 있지만 사실 둘 중 접근 속도가 더 빠른 것은 Array이다.

Array는 메모리 관리와 추가적인 오버헤드가 없으므로 더 빠르고 가볍다. 또한 크기가 고정적이므로 벡터보다 메모리 사용이 효율적이다.

Vector은 크기를 동적으로 관리하기 때문에 추가적인 오버헤드가 발생한다. 대량의 데이터를 추가할 대, 메모리를 재할당하고 데이터를 복사하는 과정에서 성능 저하가 있을 수 있다. 사용하기는 편리하지만 그 기능을 위해 많은 일을 하고 있음이다.

* 오버헤드 : 어떤 처리를 하기 위해 들어가는 간접적인 처리 시간/메모리 등

 

결론적으로 정리하면 이렇다.

  Array Vctor
크기 변경 정적 크기 동적 크기
기능(타입) 추가적인 기능 없음 크기, 삽입, 삭제 등 기능 제공
메모리 관리 사용자가 관리 STL이 알아서 관리
성능 가볍고 빠름 추가적인 오버헤드 발생

 

Vector와 Array의 사용처

위와 같은 차이 때문에 상황에 따라 Vector를 꺼내들어야할 때와 Array를 꺼내들어야할 때가 다르다.

상황 Array Vector
데이터 크기가 동적인 경우 X O
데이터 크기가 고정적인 경우 O X
성능이 중요한 경우 O X
STL 메서드와 반복자 사용이 필요한 경우 X O
메모리 사용을 엄격히 제어해야 하는 경우 O X
대규모 데이터를 처리해야 하는 경우 X O

 


 

Array의 선언

Array를 선언하고 초기화하는 방법에 대해 알아보자. Array는 선언만 할수도 있고 선언과 동시에 초기화할 수도 있다. Array를 선언하고 초기화하는데는 아래의 규칙이 적용된다.

  • 배열의 크기는 0보다 큰 정수
  • 배열의 크기는 변수를 넣을 수 없음(const가 붙은 상수만 가능)
  • 초기화를 하지 않으면 임의의 값으로 초기화되지만 부분만 초기화 하는 경우 초기화 하지 않은 값은 0으로 초기화
  • 배열 선언과 초기화를 할 때는 한 문장에서 해야함
  • 배열 선언과 초기화를 함께할 대는 배열 크기는 생략 가능(초기화한 갯수만큼 자동 설정)
  • 배열을 여러개 선언할 때는 변수 선언할 때처럼 ','로 구분
#include <iostream>
using namespace std;

int main()
{
	// array 선언하기
	int array_standard[9];
	int array_1[5], array_2[8];

	// array 선언하며 초기화하기
	double my_array_1[4] = { 1, 2, 3, 4};
	double my_array_2[] = { 1, 2, 3, 4, 5 };
	double my_array_3[6] = { 1, 2, 3 }; // {1, 2, 3, 0, 0, 0}

	// 에러 발생 상황 1
	int array_error[5];
	// array_error = { 1, 2, 3, 4, 5 }; // 에러 발생 => 선언하며 초기화할 때는 한줄에 해야함.

	// 에러 발생 상황 2
	int array_size = 5;
	//double array_error_2[array_size]; // 에러 발생 => 배열의 크기에는 배열이 들어갈 수 없음.
	const int kArraySize = 5;
	double array_error_3[kArraySize]; // 에러 발생하지 않음.

	return 0;
}

 


 

Array의 활용 시 주의사항

Array를 활용할 때 주의사항에 대해 한 가지만 설명하고 넘어가겠다. 뭔가 될 것 같지만 되지 않는 이 경우가 조금 헷갈릴 수도 있을 것 같다.

배열 복사

배열을 복사할 때는 반드시 반복문을 이용하여 하나하나 복사해야만 복사가 가능하다. 통째로 대입연산자 '='를 사용하여 복사하려고하면 에러가 발생한다. 귀찮지만 꼭 하나씩 복사해야함을 잊지 말자.

#include <iostream>
using namespace std;

int main()
{
	int array_origin[] = { 1, 2, 3 };
	int array_copy[] = { 5, 6, 7 };

	// array_origin = array_copy; // 에러 발생
    
    	// 알맞은 복사 방법
	for (int i = 0; i < 3; i++)
	{
		array_copy[i] = array_origin[i];
	}

	return 0;
}

 


 

Vctor의 선언

벡터를 사용하기 위해서는 일단 <vector> 헤더가 필요하다. 그리고 벡터의 선언, 초기화 방법은 배열과는 조금 다른 모습이니 잘 봐두어야 한다. 왜냐하면 Vector은 템플릿이기 때문이다. 벡터는 그냥 선언하는 방법, 크기만 지정하는 방법, 크기와 초기화값을 지정하는 방법이 있고 이는 Array 선언 때도 했던 것이다. 다만 다른 벡터를 가지고와 복사를 하면서 초기화하는 방법이 있다는 점이 새로운 점이다.

#include <iostream>
#include <vector>
using namespace std;

int main()
{
	// 벡터 선언
	vector<int> int_vector;
    
    	// 크기와 함께 벡터 선언
	vector<int> int_vector_with_size(5); // {0, 0, 0, 0, 0}
    
    	// 크기와 초기화값과 함께 벡터 선언
	vector<int> int_vector_with_reset(5, 2); // {2, 2, 2, 2, 2}
    
        // 벡터 선언과 복사
        vector<int> vector_copy(int_vector_with_reset); // {2, 2, 2, 2, 2}

	return 0;
}

 


 

Vctor의 사용법

vector는 array와 다르게 다양한 멤버 함수들을 제공하고 있다.

멤버함수 설명
v.assign(5, 2); 2의 값으로 5개의 원소 할당
v.at(index) index번째 원소를 참조
* v[index] 보다는 느리지만 범위를 점검하기 때문에 안전
v[index] index번째 원소를 참조
* 범위를 점검하지 않으므로 속도가 at 보다 빠름
v.front(); 첫 번째 원소를 참조
v.back(); 마지막 원소를 참조
v.clear(); 모든 원소를 제거
* 원소만 제거하고 메모리는 유지(size변경, capacity 유지)
v.push_back(7); 마지막 원소 뒤에 원소 7을 삽입
v.pop_back(); 마지막 원소를 제거
v.begin(); 첫 번째 원소를 가리킴
* Iterator와 사용
v.end(); 마지막의 "다음"을 가리킴
* Iterator와 사용
v.rbegin(); 거꾸로해서 첫번째 원소를 가리킴(reverse begin)
* Iterator와 사용
v.rend(); 거꾸로 해서 마지막의 다음을 가리킴
* Iterator와 사용
v.reserve(n); n개의 원소를 저장할 위치를 예약(미리 동적 할당)
v.resize(n); 크기를 n으로 변경
* 더 커졌을 경우 default값인 0으로 초기화
v.size(); 원소의 갯수를 리턴
v.capacity(); 할당된 공간의 크기를 리턴
v2.swap(v1); v1과 v2의 원소와 capacity를 바꿈(모든것을 스왑)
v.insert(2, 3, 4); 2번째 위치에 3개의 4를 삽입
* 뒤에 있는 요소는 뒤로 밀림
v.insert(2, 3); 2번째 위치에 3의 값을 삽입
* 삽입한 곳의 iterator를 반환
v.erase(iter); iter가 가리키는 원소를 제거
* size만 줄어들고 capacity(할당된 메모리)는 그대로
v.erase(iter, iter2); iter에서 iter2까지 범위에 있는 원소를 제거
v.empty() vector가 비었다면 true 리턴
* 기준은 size(capacity 아님)

 

size와 capacity의 차이

  • size : 할당된 메모리 안에 요소가 들어있는 갯수
  • capacity : 할당된 메모리의 크기

그렇기 때문에 두 값에는 차이가 있다. size와 capacity는 다르다!

 


 

배운 내용 정리

  • Array는 Vector와 정적/동적 크기, 기능, 메모리 관리, 성능 등에서 차이가 있다.
  • Array는 선언과 초기화가 동시에 가능하고 특정 규칙에 따른다.
  • Array는 특별한 내장 기능은 없다. 따라서 복사할 때 주의가 필요하다.
  • Vector는 선언, 크기를 지정한 선언, 크기를 지정하고 원하는 수로 초기화하며 선언이 가능하다.
  • Vector는 다양한 기능을 제공한다.
  • size와 capacity는 다르다. 

 

'C++ > 게임 개발자를 위한 C++ 문법' 카테고리의 다른 글

다중 포함 방지  (0) 2024.12.26
포인터의 개념과 사용  (0) 2024.12.26
동적 메모리 할당과 해제  (0) 2024.12.24
함수 인자 전달 방식  (0) 2024.12.23
연산 주의사항  (0) 2024.12.23