// 챕터 8-1 : vector
// Standard Template Library(STL) == '컨테이너' 라고도 불린다.
// 메모리 자동 관리가 제공되는 자료구조 라이브러리
// 템플릿 프로그래밍 기반으로, 다양한 자료형의 데이터들을 저장 할 수 있음
// TL 자료구조에는 벡터(Vector) / 맵(Map) / 셋(Set) / 스택(Stack) / 큐(Queue) / 리스트(List) 등이 있음
// 실질적으로 벡터(Vector)와 맵(Map)을 가장 많이 쓰며 가끔가다가 셋(Set)을 쓰는 정도 밖에 안된다.
// 회사에서 자신만의 컨테이너를 만들어 STL을 대체하기도 한다. class나 구조체와 비슷한 개념...?
// 하지만 STL을 기반으로 하기에 세부적인 부분을 제외하면 STL과 공용되는 부분들이 많다.
// Unreal Engine 의 경우 TArray, TMap, TMultiMap, TSet과 같은 언리얼 엔진 객체들의 전용 컨테이너가 있다.
// 벡터(Vector)
// 데이터 개수가 증가함에 따라 자동으로 메모리를 관리해주는 배열. 동적 배열 (메모리 크기를 자동으로 늘려주는 Array 라는 개념...?)
// 어떤 요소에도 임의로 접근이 가능하다(Random access) 이유 : 연속된 메모리 공간이 있기 때문...?
// 배열이 메모리 주소값을 기본으로 가지고 배열의 크기에 비례해서 어느 메모리 주소의 값에도 접근이 가능해서...?
//
// push_back() 함수 13 : 00
// 벡터(vector)의 맨 뒤에 요소를 추가한다.
// Scores.push_back(30); // 여기서 벡터는 Scores + .(접근연산자) + push_back(인자값) vector의 멤버 함수를 호출해서 인자값을 추가한다...?
// Names.push_back("Navi"); // 문자열을 넣고 싶은 경우 인자값에 ""을 넣으면 된다.
// MyCats.push_back(NewCat);
//
// pop_back() 함수
// vector의 맨 뒤에 있는 요소를 제거한다.
// 단, 비어 있는 vector에 pop)back() 함수를 호출하면 런타임 오류가 발생할 수 있다.
//
// capacity() 함수
// 저장 가능한 최대 요소 개수를 반환한다.
//
// size() 함수
// 현재 저장된 요소 개수를 반환한다.
//
// capacity() 함수 == 물통
// size() 함수 == 그 물통에 들어있는 물
//
// reserve() 함수
// reserve(size_t _Newcapacity) == vector의 현재 capacity(저장 가능한 최대 요소 개수)를 수정(reserve)한다.
// Scores.reserve(10u); == Scores라는 벡터의 메모리 범위를 (10u) 10 칸 만큼 (reserve) 늘려줘
// _Newcapacity가 기존 capacity보다 작은 경우(_Newcapacity < capacity)에는 아무 일도 발생하지 않는다. == false, 줄이는 건 불가능.
// _Newcapacity가 기존 capacity보다 큰 경우(capacity < _Newcapacity)에는 메모리 재할당이 발생한다. == true, 늘리는 건 가능
//
// 벡터의 저장 가능한 최대 요소 개수를 늘리는 건 가능하지만 줄이는 건 불가능하다.
//
// 벡터의 size가 커지다가 capacity를 넘어서게 될 경우
// 메모리를 동적할당한 뒤 그 곳으로 기존 데이터를 모두 복사된다.
// 이런 재할당이 비용이 들어갑니다.
// 욕조에 물이 가득 찼을 때 물을 더 채워넣으려면 새 욕조에 물을 전부 옮기는 수고로움과 비슷함.
// 벡터를 사용할 때는 처음부터 크게 잡고 사용하는게 바람직하다.
// 이때 사용하는 함수가 reserve() 함수이다.
//
// resize(const size_t _Newsize)
// vector의 size(현재 저장된 요소 개수)를 수정하고 새로 생긴 데이터는 0에 준하는 값으로 초기화 한다.
// reserve == capacity 함수의 값을 늘리는 함수(값을 초기화 하지 않음)
// resize == size 함수의 값을 늘리는 함수(값을 0에 준하는 값으로 초기화함)
//
// _Newsize가 기존 size보다 작은 경우(_Newsize < size)에는 초과분을 삭제한다. 물의 양을 새로 대입시켰으니 그 초과분은 버리는 것.
// (size < _Newsize && _Newsize < capacity) 정상 추가 == 현재 저장된 요소 개수가 새로 정의된 저장 요소 개수보다 작고, 새로 정의된 저장 요소 개수가 저장 가능한 최대 요소보다 작을 때 true
// _Newsize가 기존 capacity보다 큰 경우(capacity < _Newsize)에는 메모리 재할당이 발생. == 물을 다 채워넣지 못해서 새 물통으로 물을 옮기는 것.
//
// 예시 : Scores.resize(10u); == Scores라는 이름의 클래스의 멤버 vector의 배열의 현재 저장 요소를 10으로 재정의한다.
//
// clear() 함수
// vector를 싹다 지운다 크기(size)는 0이 되고 용량(capacity)은 변하지 않는다.
//
// 예시 : Scores.clear();
//
// Main.cpp
//
#include <vector>
#include <iostream>
int main()
{
std::vector<int> Scores; // 벡터를 선언 후 <> 안에 원하는 자료형에 맞는 클래스를 자동으로 만든다.
// int형 자료들을 저장하는 클래스 vector를 기반으로 Scores라는 이름의 객체로 배열 선언
// 클래스명 객체명; 과 동일하다.
// 이 줄 까지는 Scores의 vector의 capacity(저장 가능 개수)는 0이다.
Scores.reserve(8u);
// Scores 라는 이름의 클래스의 멤버에 접근해서(. 접근연산자) vector 배열의 메모리 공간을 늘린다(reserve) 8만큼(8u)
// 이 줄 부터 저장 가능 개수는 8이다.
Scores.push_back(100);
// Scores 라는 이름의 클래스의 멤버에 접근해서 vector 배열의 메모리 공간 중 맨 뒤에 100을 넣는다.
Scores.push_back(98);
// 그 다음으로 98을 넣는다.
std::cout << "Current capacity : " << Scores.capacity() << std::endl;
// Scores 라는 이름의 클래스의 멤버에 접근해서 vector 배열의 메모리 공간의 최대 저장 요소 개수를 출력한다.
// vector 안에 값을 넣었다고 해서 최대 저장 개수가 변동하지는 않는다.
std::cout << "Current size: " << Scores.size() << std::endl;
// Scores 라는 이름의 클래스의 멤버에 접근해서 vector 배열의 메모리 공간에 저장된 요소 개수를 출력한다.
for (size_t i = 0; i < Scores.size(); ++i) // size_t == 음수를 표현하지 않는 unsigned 타입 자료형.
// 음수값을 포함시킬 수 없는 자료형 size_t를 지니고 있는 변수 i가 Scores 라는 클래스의 vector의 배열의 저장된 요소 개수(size)보다 작은 동안 true
{
std::cout << "Scores[" << i << "] : " << Scores[i] << std::endl;
// Scores 라는 자료형의 멤버로 포함되어 있는 vector의 배열 중 i 번째 메모리주소의 값을 출력해라.
// 예상 출력물 : Scores[0] : 100, Scores[1] : 98
}
Scores.pop_back(); // Scores 클래스의 멤버인 vector의 배열 중 맨 뒤에 있는 요소를 제거한다(pop_back)
std::cout << "Current capacity: " << Scores.capacity() << std::endl;
std::cout << "Current size: " << Scores.size() << std::endl;
for (size_t i = 0; i < Scores.size(); ++i)
{
std::cout << "Scores[" << i << "] : " << Scores[i] << std::endl;
}
// 예상 출력물 : Scores[0] : 100
// 동적할당을 했을 경우
// delete[] Scores;
// scores = nullptr;
// 을 해야한다.
return 0;
}
// Main.cpp
#include <iostream>
#include <vector>
void PrintScores(const std::vector<int>& InScores); // 전방선언
// 읽기전용(const)에 참조자인 InScores를 매개변수로 둠.
int main()
{
std::vector<int> Scores01;
// Scores01 이라는 이름의 클래스에 멤버로 int 자료형을 저장하는 배열 vector를 선언한다.
Scores01.reserve(4u);
// Scores01의 vector에 4칸 만큼 최대 저장 요소를 정의한다.
// Scores01의 vector 배열의 맨 뒤의 메모리주소에 값을 넣는다(push_back)
Scores01.push_back(100); // Scores01[0] = 100;
Scores01.push_back(98); // Scores01[1] = 98;
Scores01.push_back(70); // Scores01[2] = 70;
Scores01.push_back(86); // Scores01[3] = 86;
PrintScores(Scores01); // PrintScores 함수를 호출하고 그 인자값으로 Scores01을 제공한다.
// 예상출력물 : capacity == 4, size == 4, Scores01의 배열의 0, 1, 2, 3 다 출력
Scores01.resize(2u);
// Scores01의 멤버 벡터의 저장된 요소 개수를 2로 재정의한다.
PrintScores(Scores01);
// 예상출력물 : capacity == 4, size == 2, Scores01의 배열의 0, 1 출력
Scores01.clear();
// Scores01의 멤버 벡터의 저장된 요소를 전부 버린다.
PrintScores(Scores01);
// capacity == 4, size == 0, Scores01의 배열 출력 없음
return 0;
}
void PrintScores(const std::vector<int>& InScores)
{
// InScores == Scores01
std::cout << "Current capacity: " << InScores.capacity() << std::endl; // Scores01의 현재 최대 저장가능한 요소 개수를 반환(capacity)
std::cout << "Current size: " << InScores.size() << std::endl; // Scores01의 현재 저장된 요소 개수를 반환
for (size_t i = 0; i < InScores.size(); ++i)
{
std::cout << "InScores[" << i << "] : " << InScores[i] << std::endl;
}
}