2025. 4. 15. 23:00ㆍProgramming Language/C++
1. std::vector
std::vector를 보기 이전에 std::array의 경우는 정적배열을 사용한 C++스타일의 배열로 컴파일 시점에 크기가 정해져있어야하는 형태의 타입이였다.
그리고 정적배열을 활용했기에 메모리의 stack 부분에 주로 할당이 되게 된다.
#include <iostream>
#include <array>
int main() {
std::array<int, 3> array = { 1, 2, 3 };
}
이렇게 사이즈가 컴파일 시점에 지정되어 있어야 하기에
이런 사용이 불가능하다.
반면 이번에 배울 std::vector의 경우는 정적할당이 아니라 동적할당을 사용하기에 컴파일 시점에 크기가 지정되어 있지않아도 된다.
먼저 vector의 간단한 사용법부터 확인해보자.
2. std::vector의 사용법
std::array의 경우는 array를 include 해줘야만 사용이 가능 했듯이
#include <array>
std::vector의 경우도 vector를 include해줘야만 사용이 가능하다.
#include <vector>
기본적인 vector의 문법은
std::vector<타입> 변수명(크기);
와 같이 선언이 가능하다.
그리고 이렇게 선언한 vector는 기본적으로 모든 항목이 0으로 초기화가 되어 있다.
이를 확인해보자면 for문을 통해서 vector의 크기만큼 순회하면서 출력해주면
이렇게 0으로 초기화되어 있는 모습을 볼 수 있다.
또한 값을 하나하나 지정하면서 선언도 가능하다
std::vector<int> vec {1, 2, 3};
이렇게 하면 초기화한 값에 맞게 크기가 지정되어 선언이 된다.
1) 컴파일 타입에 사이즈를 몰라도 됨
vector의 경우는 동적할당되기에 컴파일 타임에 사이즈가 정해져 있지 않아도 사용이 가능하다.
예를 들어 사용자의 입력을 통해 사이즈가 정해지는 경우
이렇게 사용하더라도
사용과 컴파일 시점에 문제가 전혀 없다는 것을 확인할 수 있다.
2) 선언 시점에 하나의 값으로 초기화하기
vector를 선언할때
이 부분에서 10 다음 전달인자로 어떤 값을 전달하면 그 값으로 모든 vector의 요소를 초기화해준다.
이렇게 두번째 인자로 20을 전달하면
모든값이 전달한 값으로 초기화되는 것을 확인할 수 있다.
3) 실행 이후에 사이즈를 조절할 수 있음
vector에 resize(크기)라는 함수를 사용하면 실행되면서 vector의 사이즈를 바꾸는 것도 가능하다.
이 경우에 만약 초기에 선언하면서 20을 모두 초기화하기로 설정되었다면 늘어나는 요소들은 초기값인 0을 가진채 추가된다
여기서 resize에서도 두번째 인자로 값을 추가하면 그 값으로 추가된 값들에 대해서 초기화를 해준다.
4) 실행 시점에 크기를 늘리면서 값을 넣거나 크기를 줄이면서 값을 뺄수도 있다.
vector의 경우는 크기를 늘리면서 값을 가장 뒤에 추가하는 것도 가능한데 이때 사용하는 함수가 push_back(값)이라는 함수이다.
반대로 가장 마지막 값을 빼면서 vector의 크기를 줄일 수도 있는데 이 기능을 하는것은 pop_back()이라는 함수이다
이렇게 왠만하면 vector를 사용하면 사용이 편해진다.
그러나 성능이 필요하다면 정적배열인 std::array를 사용하는게 좋을 수도 있다.
왜냐면 내부적으로 사이즈가 변경될때마다 더 큰 배열로 할당을 해야하기 때문에 재할당이 이뤄지는 상황들로 인해서 성능의 저하가 발생할수도 있게 되기 때문이다.
이렇게 루프문을 돌면서 크기가 커질때마다 vector의 크기(vector.size())와 해당 vector의 주소값을 확인해보면(vector.data(): vector의 첫번째 요소가 가리키는 주소값을 반환함)
크기가 커질때마다 주소값이 변경되는 것을 보았을때 아예 전체를 재할당하는 상황들이 존재하는 것을 볼 수 있다.
크기가 커질때 재할당이 안되는 경우가 있는 이유
vector는 내부적으로 size와 capacity를 따로 관리하는데
size는 vector가 실제로 담고 있는 원소의 갯수이고, capacity는 vector가 확보한 메모리 공간인데 확보한 capacity가 여유가 있는 경우에는 재할당을 시키지 않는다.
예를 들어 위에 있는 사이즈 증가를 보았을때
// size가 1인 vector
vec.size(): 1
vec.data(): 01601E48
// size가 2인 vector, 재할당되었기에 이전 capacity가 1이였다는 것을 확인할 수 있음
vec.size(): 2
vec.data(): 016037B0
// size가 3인 vector, 재할당되었기에 이전 capacity가 2이였다는 것을 확인할 수 있음
vec.size(): 3
vec.data(): 01603350
// size가 4인 vector, 재할당되었기에 이전 capacity가 3이였다는 것을 확인할 수 있음
vec.size(): 4
vec.data(): 01601E48
// size가 5인 vector, 재할당되었기에 이전 capacity가 4이였다는 것을 확인할 수 있음
vec.size(): 5
vec.data(): 015F6E40
// size가 6인 vector, 재할당되지 않았기에 capacity가 6이상임을 확인할 수 있음
vec.size(): 6
vec.data(): 015F6E40
// size가 7인 vector, 재할당되었기에 이전 capacity가 7이였다는 것을 확인할 수 있음
vec.size(): 7
vec.data(): 016019A8
// size가 8인 vector, 재할당되지 않았기에 capacity가 8이상임을 확인할 수 있음
vec.size(): 8
vec.data(): 016019A8
// size가 9인 vector, 재할당되지 않았기에 capacity가 9이상임을 확인할 수 있음
vec.size(): 9
vec.data(): 016019A8
...
이런식으로 capacity가 크게 잡힌 경우에는 재할당되지 않고 여유만큼의 크기를 늘려 기존의 위치에서 추가로 늘어나기만 하게 된다
여기서 reserve(크기)라는 함수를 사용하게 되면 vector의 capacity를 어느정도 크기를 줄것인지를 지정해서 크기가 늘어날때 마다 재할당이 일어나지 않게 만들 수 도 있다.


나중에 표준 라이브러리를 배우면서 배울 내용이니 이런 내용이 있다는 부분만 이해하고 넘어가자.
5) 크기가 달라도 복사 저장이 가능하다
3. std::array에서 사용하던 연산을 사용할 수 있는 vector
vector에서도 array가 사용하던 연산을 사용할수가 있다.
1) vector.size() : vector의 크기 반환
위에서도 많이 사용했다 싶이 size()함수는 vector의 크기를 반환한다.
2) vector.at(i) : 범위검사를 포함한 요소 접근([i]보다 느림)
array 처럼 요소에 접근을 할 수 있는 방법으로 []로 접근하면 out of range에 대한 exception을 발생시키지 않으나 at(i)로 접근하는 경우는 out of range exception을 발생시켜 런타임 시점에 오류를 감지할 수 있다.
# at(i)를 사용했을때 out of range Exception


결과로 에러임을 확인할 수 있음.
# []을 사용했을때 out of range Exception


정상 작동한것과 같이 보인다
3) vector[ i ] : 범위 검사 없는 요소 접근(at(i)보다 빠름)
4) vector.front() : 첫 번째 원소 반환
5) vector.back() : 마지막 원소 반환
6) vector.data() : 내부 배열 주소(vector 내부 로직에서 사용되는 배열 주소)를 반환
vector의 내부에 로직에서는 어찌됐건 배열을 사용해야만 배열 처럼 사용할 수 있기에 내부엔 배열을 사용하게 되는데 그 배열의 주소값을 반환하는 함수가 data()함수이다.
7) vector.swap(vector2) : vector2의 내용과 vector 내용을 교환한다.
다만 array에서 사용하던 fill()의 경우는 vector에서 사용할 수 없다
4. vector에서만 사용가능한 연산
array에는 없지만 vector에서만 존재하는 연산들이 존재한다.
1) push_back(value) : 맨 뒤에 요소 추가(크기도 늘어남)
2) pop_back() : 맨 뒤 요소 제거(크기도 줄어듦)
3) resize(size, [value]) : 크기 변경
두번째 전달인자가 존재 하지 않을 경우 0으로 초기화된 요소가 추가됨
두번째 전달인자를 전달 할 경우 해당 값으로 초기화된 요소가 추가됨
4) capacity() : 내부 매모리 용량 확인(capacity 확인)
5) reserve(size) : 내부 용량을 미리 확보(capacity 확보)
등등이 존재한다.
추가적으로 이것 저것 더 있으니 필요하다면 확인해보길 바란다.
'Programming Language > C++' 카테고리의 다른 글
Ch 09. 함수 - 01. 함수의 기본 (0) | 2025.04.16 |
---|---|
Ch 08. 참조 - 01. 참조(Reference) (0) | 2025.04.16 |
Ch 07. 포인터 - 06. void pointer (0) | 2025.04.15 |
Ch 07. 포인터 - 05. nullptr (0) | 2025.04.15 |
Ch07. 포인터 - 04.동적 할당 (0) | 2025.04.10 |