C++ vector, array, 배열
목차
C++ 에는 배열을 사용하기 위한 몇가지 객체가 준비되있습니다. 이번 포스팅에는 배열의 세가지 방법들을 비교해보겠습니다.
각각의 자세한 메소드 사용법은 아니고 배열을 표현하는 방법들을 대강 살펴보겠습니다.
우선 C++의 기본 자료형인 배열이 있습니다. int myArray[3] 처럼 그냥 문법이죠. 기본적으로는 스택 메모리를 사용하지만 new 로 동적 할당후 포인터로 사용합니다. 또 배열의 이름은 배열 전체에 대한 포인터 입니다. myArray 는 int형 3개인 12바이트에 대한 포인터입니다. 이 배열은 함수에 넘겨서 포인터로 받을 수 있습니다.
다음은 vector 입니다. vector 템플릿 클래스는 string 과 유사합니다. string 클래스는 생성자에 문자열을 받아서 자동으로 크기를 계산하는 동적 할당을 합니다. vector 도 자동으로 동적할당을 합니다. 그런데 string 보다 형태가 훨씬 자유롭습니다. string 은 문자열에 대해서만 저장이 가능하지만 vector 클래스는 < > 이 안에 어떤 데이터 형도 집어 넣을 수 있습니다. double, int, 혹은 구조체나 클래스도 가능합니다.
여기서 자세히 다루지는 않겠지만 vector 배열에는 데이터를 조작하는 여러가지 메소드가 있습니다. 기본적으로는 배열 처럼 [ ] 인덱스 사용이 가능합니다만, 런타임 에러를 방지하기 위해 적절한 메소드를 사용하는 것이 좋습니다. 메소드 레퍼런스는 참고문서에서 확인할 수 있습니다.
다음 array 객체입니다. array 배열 객체? 배열이 있는데 또 배열이다?
C++의 배열은 원초적인 자료형이기 때문에 메소드가 없습니다. 파이썬 같은 최신의 언어들은 기본적으로 자료형들을 객체로 감싸서 나오기 때문에 여러가지 내장 함수(built-in function)를 지원하는데요.
array 클래스는 랩퍼 클래스(Wrapper Class) 라고 볼 수 있습니다. 이것을 STL 에서는 컨테이너라고 합니다. 컨테이너는 무역 컨테이너 처럼 어떤 자료를 담는 박스같은 것 입니다. vector 도 array 도 컨테이너 입니다. 때문에 비슷한 속성과 메소드를 가지고 있습니다.
다만 array 는 new나 delete 를 사용하지 않습니다. 아래 예제를 실행해보면 일반 배열과 array 객체의 메모리가 인접해 있음을 볼 수 있습니다(시스템에 따라 차이있음)
아래는 세가지 종류 배열을 사용하는 예제입니다.
#include <iostream> #include <vector> #include <array> using namespace std; int main() { vector<double> myVector(3); // vector template cout << "\n[------------- Vector -------------]\n"; myVector[0] = 1.0 / 3.0; myVector[1] = 1.0 / 4.0; myVector[2] = 1.0 / 5.0; cout << "myVector[0] : " << myVector[0] << " at " << &myVector[0] << endl; cout << "myVector[1] : " << myVector[1] << " at " << &myVector[1] << endl; cout << "myVector[2] : " << myVector[2] << " at " << &myVector[2] << endl; // array cout << "\n[------------- Array -------------]\n"; double myArray[3] = { 1.3, 5.7, 2.2 }; cout << "myArray[0] : " << myArray[0] << " at " << &myArray[0] << endl; cout << "myArray[1] : " << myArray[1] << " at " << &myArray[1] << endl; cout << "myArray[2] : " << myArray[2] << " at " << &myArray[2] << endl; // array template cout << "\n[------------- Array Object -------------]\n"; array<double, 3> objArray = { 3.7, 2.9, 1.3 }; cout << "objArray[0] : " << objArray[0] << " at " << &objArray[0] << endl; cout << "objArray[1] : " << objArray[1] << " at " << &objArray[1] << endl; cout << "objArray[2] : " << objArray[2] << " at " << &objArray[2] << endl; cout << objArray.at(0) << endl; cout << objArray.at(1) << endl; cout << objArray.at(2) << endl; return 0; }
[------------- Vector -------------] myVector[0] : 0.333333 at 007D5FA8 myVector[1] : 0.25 at 007D5FB0 myVector[2] : 0.2 at 007D5FB8 [------------- Array -------------] myArray[0] : 1.3 at 006FF708 myArray[1] : 5.7 at 006FF710 myArray[2] : 2.2 at 006FF718 [------------- Array Object -------------] objArray[0] : 3.7 at 006FF6E8 objArray[1] : 2.9 at 006FF6F0 objArray[2] : 1.3 at 006FF6F8 3.7 2.9 1.3
세종류 다 [] 인덱스를 사용할 수 있습니다. 인덱스를 사용할 수 있는 컨테이너는 선형 시퀀스(linear sequence) 라고 합니다. 인덱스는 정수 0부터 1씩 자동으로 증가합니다.
C++에서 인덱스는 일종의 포인터 피연산자 입니다. +1 은 그 데이터 타입만큼 주소를 이동하라는 지시입니다. 그런데 C++ 컴파일러는 범위를 벗어난 인덱스를 검사하지 않습니다. 예를 들어 요소가 3개인 배열에 myArray[3] 이라고 하면 0, 1, 2 에서 벗어나는데 컴파일러는 그냥 놔둡니다. 런타임도 잡지 않습니다.
원초적 배열을 사용하면 이런 문제가 발생합니다. 물론 범위를 넘어가지 않도록 하는 로직을 짜넣을 수 있겠죠. 이런 경우 array 객체에서 제공하는 at을 사용하면 런타임 오류를 발생시키기 때문에 예외 처리를 만들 수 있습니다.
요약
C++ vector는 STL 클래스 입니다. STL 을 초급과정에서 다 이해하기는 조금 어렵습니다. 원래 기초를 배운 후 STL을 별도로 해야하는데 내용이 많습니다. 자바로 비교하면 컬렉션인데요. 컬렉션도 자바 입문과정의 후반부에 배우게 됩니다.
여기서는 대강적으로 배열 관련 객체들을 소개해봤습니다.
참고문서
vector – C++ Reference (cplusplus.com)
Vector in C++ STL – GeeksforGeeks
array – C++ Reference (cplusplus.com)
array 클래스(C++ 표준 라이브러리) | Microsoft Docs