C++ vector, array 객체 | C++ 자습서 19

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

Leave a Comment