벡터란?
: std::vector is a sequence container that encapsulates dynamic size arrays.
벡터는 연속적인 컨테이너인데 dynamic size array를 캡슐화 한 것 이란 뜻이다.
Dynamic size array를 벡터를 사용하지 않고 만드는 법은 cpp를 어느정도 공부했다면 알고 있을 것이다.
int main()
{
int* numsPtr = new int[5];
for (int i = 0; i < 5; i++)
{
numsPtr[i] = i;
}
delete numsPtr;
};
이렇게 int형 포인터를 만들고 for문을 통해 숫자를 넣어주고 delete를 통해 할당 해제해주면 된다.
그림으로 보면,
스택 위에 numsptr이란 포인터가 만들어지고 힙 공간에 5개의 연속적인 메모리 공간이 만들어진다.
그 공간 안에 0~4의 숫자가 각각 할당되고 numptr은 힙에 만들어진 이 연속적인 메모리 공간을 가리키게 된다.
하지만 이에는 위험성이 있는데,
delete를 잊게 되면 메모리 릭이 일어날 수 있고 제약이 있다..
c++ stl에서는 c++ dynamic array를 관리해 주는 컨테이너를 제공해 주는데 이것이 vector이다.
위의 코드를 벡터를 활용해서 다시 만들어 보면,
#include <vector>
int main()
{
std::vector<int> nums(5);
for (int i = 0; i < 5; i++)
{
nums[i] = i;
}
};
이를 그림으로 메모리 구조를 보면,
nums 오브젝트가 생기고 힙 위에 똑같이 5칸의 연속적인 메모리 공간이 생기면서 0,1,2,3,4 가 들어오게 되는 것이고,
vector 오브젝트 nums는 이 공간을 가리키게 되는 것이다.
여기서 벡터를 사용했을 때 장점은,
1) delete 키워드를 사용하지 않고 stack에서 nums가 없어질 때 자동적으로 힙 위에 있는 메모리 공간이 리턴되면서
메모리 릭이 일어나지 않는다는 것
2) 힙 위에 있는 nums 공간을 초기화해주기 위해 for문을 굳이 쓸 필요 없이 std::vector<int> nums{0,1,2,3,4}
이런 식으로 초기화 해주는 것도 가능하다는 것.
벡터에서만 할 수 있는 일
벡터에서는 대표적으로 다음과 같은 함수들을 호출해줄 수 있다.
#include <vector>
#include <iostream>
int main()
{
std::vector<int> nums{ 0,1,2,3,4 };
std::cout << nums.size() << std::endl;
nums.emplace_back(5);
std::cout << nums.size() << std::endl;
nums.pop_back();
std::cout << nums.size() << std::endl;
};
벡터의 size() 함수를 콜 해보자.
즉, 벡터의 size()는 현재 컨테이너가 가지고 있는 element 요소의 개수를 리턴해준다.
다음으로는 벡터의 emplace_back() 함수를 콜 해보자.
nums.emplace_back(5);
함수를 통해서 5 숫자를 넣어주면 벡터 array 안에 마지막 공간에 하나를 더 만들어 주고
이 마지막 공간에 emplace_back(i); 으로 넘어온 요소 i를 삽입해 주는 것이다.
이렇게 되면 전체 요소의 개수가 하나가 더 늘어날 것이고
빌드해서 확인해 보면 벡터의 사이즈가 6으로 늘어난 것을 확인할 수 있다.
벡터의 pop_back() 함수를 콜 해보자.
nums.pop_back();
벡터 array의 마지막 공간을 없애주면서 다시 예전 상태로 돌아가는 것이다.
벡터의 사이즈도 하나가 줄어들 것이다.
실행해보면 사이즈가 다시 5로 줄어든 것을 확인할 수 있다.
벡터를 iterate 하는 방법
주로 많이 쓰는 방법은 다음과 같이 두 가지 방법이 있다.
첫 번째 방법을 써도 되고 두번째 방법을 써도 되는데,
#include <vector>
#include <iostream>
int main()
{
std::vector<int> nums{ 1,2,3,4};
nums.emplace_back(5);
for (std::size_t idx = 0; idx<nums.size(); idx++)
{
std::cout << nums[idx] << std::endl;
}
for (auto itr = nums.begin(); itr = !nums.end(); itr++)
{
std::cout << (*itr) << std::endl;
}
};
벡터를 iterate하는 가장 좋은 방법은 ranged for 을 사용하는 것이 가장 좋다.
#include <vector>
#include <iostream>
int main()
{
std::vector<int> nums{ 1,2,3,4};
nums.emplace_back(5);
//ranged for
for (const int& num : nums)
{
std::cout << num << std::endl;
}
};
ranged for loop 참고: https://nybot-house.tistory.com/61
참고로 어셈블리어를 확인해 보면 위 세 방식은 모두 동일하다.
클래스로 벡터 만들기
마지막으로 클래스를 따로 정의하는 경우
다음과 같이 고양이 클래스의 vector 또한 만드는 것이 가능하다.
#include <vector>
#include <iostream>
class Cat
{
public:
explicit Cat(int age) : mAge{ age } {}
void speak() const
{
std::cout << "meow~" << mAge <<std::endl;
}
private:
int mAge;
};
int main()
{
std::vector<Cat> cats;
cats.emplace_back(Cat(1));
cats.emplace_back(Cat(2));
cats.emplace_back(Cat(3));
cats.emplace_back(Cat(4));
for (const auto& cat : cats)
{
cat.speak();
}
};
고양이를 여러마리를 넣어주고 벡터 배열 안에 있는 각 고양이에 대해서 멤버 함수를 호출하는 코드도 가능해지는 것이다.실행해보면 다음과 같이 1살짜리 고양이~ 4살짜리 고양이가 meow 외치는 것을 확인할 수 있다.
'모던C++ > 벡터, 배열 Vector, Array' 카테고리의 다른 글
4. 벡터 루프문 vector array for loop_C++ (0) | 2022.11.20 |
---|---|
3. 벡터 메모리 (reserve, size, capacity, noexcept)_ C++ (0) | 2022.11.08 |
2.1> 벡터의 emplace_back(), push_back() _C++ (0) | 2022.11.08 |
2. 벡터 vector 의 기본 (Time Complexity 시간 복잡도)_C++ (0) | 2022.11.06 |