고정 크기 vector
- vector를 사용하는 가장 쉬운 방법은 고정 크기 배열처럼 사용하는 것
- 마지막 원소에 접근하는 방법은 operator [] 말고도 at(), front(), back() 메서드가 있다.
- at()은 경계 검사를 수행해서 인덱스가 범위를 벗어나면 out_of_range 익셉션을 던짐
- front()와 back()은 첫 번째와 마지막 원소에 대한 레퍼런스 리턴
최고점이 100이 되도록 시험 점수를 정규화 하는 프로그램
#include <cstddef>
#include <vector>
#include <iostream>
#include <limits>
using namespace std;
int main()
{
vector<double> doubleVector(10); // double 값 열 개를 담은 vector를 생성한다.
// 최댓값(max)을 double의 최솟값으로 초기화한다.
double max = -numeric_limits<double>::infinity();
for (size_t i = 0; i < doubleVector.size(); i++) {
cout << "Enter score " << i + 1 << ": ";
cin >> doubleVector[i];
if (doubleVector[i] > max) {
max = doubleVector[i];
}
}
max /= 100.0;
for (auto& element : doubleVector) {
element /= max;
cout << element << " ";
}
cout << endl;
return 0;
}
동적 크기 vector
- vector의 진가는 크기가 동적으로 조절된다는 데 있다.
- 위의 프로그램에서 입력하는 점수의 개수에 제한이 없다고 가정
#include <cstddef>
#include <vector>
#include <iostream>
#include <limits>
using namespace std;
int main()
{
vector<double> doubleVector; // double 값 열 개를 담은 vector를 생성한다.
// 최댓값(max)을 double의 최솟값으로 초기화한다.
double max = -numeric_limits<double>::infinity();
for (size_t i = 1; true; i++) {
double temp;
cout << "Enter score " << i << " (-1 to stop): ";
cin >> temp;
if (temp == -1) {
break;
}
doubleVector.push_back(temp);
if (temp > max) {
max = temp;
}
}
max /= 100.0;
for (auto& element : doubleVector) {
element /= max;
cout << element << " ";
}
cout << endl;
return 0;
}
생성자와 소멸자
- 디폴트 생성자는 원소가 0개인 vector를 생성함
- 원소 수와 초깃값 설정 가능
vector<int> inVector; // 원소 수가 0인 int 타입의 vector 생성
vector<int> intVector(10, 100); // int형 백터 10칸 모두 100으로 초기화
vector<string> stringVector(10, "hello");
vector의 복제와 대입
- vector는 객체의 복제본을 저장함.
- 복제 생성자와 대입 연산자는 vector의 원소를 복제할 때 깊은 복제를 수행
- 성능을 높이려면 함수 또는 메서드에 vector를 전달할 때 레퍼런스나 const 레퍼런스로 전달하자
// 두 vector의 내용을 상수 시간에 맞바꾸는 swap() 메서드
vector<int> v1(10);
vector<int> v2(5, 100);
v1.swap(v2);
// 결과
// v1은 값이 100인 원소 5개를 갖게 되고,
// v2는 값이 0인 원소 10개를 갖게 된다.
vector 비교
- 자주 사용하는 비교 연산자를 오버로딩한 버전을 제공함.
- int type과 vector를 비교하는 예시를 보자
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector<int> vectorOne(10);
vector<int> vectorTwo(10);
if (vectorOne == vectorTwo) {
cout << "equal!" << endl;
} else {
cout << "not equal!" << endl;
}
vectorOne[3] = 50;
if (vectorOne < vectorTwo) {
cout << "vectorOne is less than vectorTwo" << endl;
} else {
cout << "vectorOne is not less than vectorTwo" << endl;
}
return 0;
}
// 실행 결과
// equal!
// vectorOne is not less than vectorTwo
for (vector<double>::iterator iter = begin(doubleVector); iter != end(doubleVector); ++iter) {
*iter /= max;
cout << *iter << " ";
}
가능하면 후행 증가 보다는 선행 증가를 지정하는 것이 좋다. 후행 증가는 새로운 반복자 객체를 리턴하는 반면, 선행 증가는 레퍼런스만 리턴하기 때문이다!
// auto 키워드를 사용한 버전, 이 코드를 사용하려면 앞에 나온 for문을 주석처리한다.
for (auto iter = begin(doubleVector); iter != end(doubleVector); ++iter) {
*iter /= max;
}
#include <vector>
#include <string>
#include <iostream> // for cout
using namespace std;
int main()
{
vector<string> stringVector(10, "hello");
for (auto it = begin(stringVector); it != end(stringVector); ++it) {
it->append(" there");
cout << *it << endl;
}
// 범위 기반 for문을 사용한 버전
for (auto& str : stringVector) {
str.append(" there");
cout << str << endl;
}
return 0;
}
vector<int> intVector;
auto iter = end(intVector);
*iter = 10; // 버그, iter가 벡터의 원소를 가리키고 있지 않음
#include <vector>
using namespace std;
int main()
{
vector<int> vectorOne(10);
vector<int> vectorTwo(10);
// 벡터에 원소를 채운다.
// 버그! 무한 루프에 빠질 수 있다.
for (auto iter = begin(vectorTwo); iter != end(vectorOne); ++iter) {
// 루프 본문
}
return 0;
}
#include <vector>
using namespace std;
int main()
{
vector<int> intVector(10);
auto it = begin(intVector);
it += 5;
--it;
*it = 4;
return 0;
}
vector에 레퍼런스 저장하기
- vector와 같은 컨테이너에 레퍼런스를 저장할 수도 있다.
#include <vector>
#include <string>
#include <functional>
#include <iostream>
using namespace std;
int main()
{
string str1 = "Hello";
string str2 = "World";
// string에 대한 레퍼런스를 담은 vector를 생성한다.
vector<reference_wrapper<string>> vec{ ref(str1) };
vec.push_back(ref(str2)); // push_back()에도 적용할 수 있다.
// 앞에서 만든 vector의 두 번째 원소(레퍼런스)가 참조하는 string 값을 변경한다.
vec[1].get() += "!";
// 최종 결과(변경된 str2 값)를 출력한다.
cout << str1 << " " << str2 << endl;
}
원소 추가와 삭제
- push_back() 메서드 : 원소를 맨 뒤에 추가
- pop_back() 메서드 : 원소 삭제
- pop_back() 메서드는 삭제한 원소를 리턴하지 않는다. back() 메서드로 미리 받아두자.
insert() 메서드 : 원하는 지점에 원소 추가
erase() 메서드 : vector에 원소 중 원하는 것을 삭제
// 인수를 두 개 받는 버전의 erase()와 세 가지 버전의 insert() 예시
#include <vector>
#include <iostream>
using namespace std;
template<typename T>
void printVector(const vector<T>& v)
{
for (auto& element : v)
{
cout << element << " ";
}
cout << endl;
}
int main()
{
vector<int> vectorOne = { 1, 2, 3, 5 };
vector<int> vectorTwo;
// 앞에서 vectorOne을 초기화할 때 깜박 잊고 넣지 않은 4를 여기서 추가한다.
vectorOne.insert(cbegin(vectorOne) + 3, 4);
// vectorTwo에 6부터 10까지의 원소를 추가한다.
for (int i = 6; i <= 10; i++) {
vectorTwo.push_back(i);
}
printVector(vectorOne);
printVector(vectorTwo);
// vectorTwo의 원소를 모두 vectorOne 뒤에 추가한다.
vectorOne.insert(cend(vectorOne), cbegin(vectorTwo), cend(vectorTwo));
printVector(vectorOne);
// vectorOne에서 2부터 5까지 삭제한다.
vectorOne.erase(cbegin(vectorOne) + 1, cbegin(vectorOne) + 5);
printVector(vectorOne);
// vectorTwo를 완전히 비운다.
vectorTwo.clear();
// 100에 대한 복제본 10개를 추가한다.
vectorTwo.insert(cbegin(vectorTwo), 10, 100);
// 마지막 원소를 제거해서 원소를 9개만 남긴다.
vectorTwo.pop_back();
printVector(vectorTwo);
return 0;
}
#include <cstddef>
#include <vector>
using namespace std;
vector<int> createVectorOfSize(size_t size)
{
vector<int> vec(size);
int contents = 0;
for (auto& i : vec) {
i = contents++;
}
return vec;
}
int main()
{
vector<int> myVector;
// 이동 의미론을 지원하므로 이동 대입 연산자를 호출함.
myVector = createVectorOfSize(123);
return 0;
}
vec.emplace_back(5, 'a');
vector의 메모리 할당 방식
- vector에 원소를 추가하면 자동으로 메모리가 할당된다.
- 추상화 원칙에 따라 vector의 내부 메모리 할당 방식을 알 필요가 없지만
1. 효율성 : 재할당이 발생하면 선형 시간의 복잡도를 가질 수 있다.
2. 반복자 무효화 : 메모리 재할당 시, 기존의 반복자들이 모두 무효화 됨
공간을 미리 확보하기 위한 방법
reserve() 메서드 호출하기 : 지정한 수의 원소를 충분히 담을 만큼의 공간 할당
vector에 담길 원소 수를 vector 생성자나 resize() or assign() 메서드로 지정 : 원하는 크기의 vector 생성, 용량도 적절히 설정
vector<int> vec { 1, 2, 3 };
int* data1 = vec.data();
int* data2 = data(vec);