[C++] Vector 사용법 ( 삽입, 삭제, 검색, 공간 관리, call by reference )

2021. 4. 6. 14:33개발 관련/c++

Vector은 java의 ArrayList와 비슷하다.

add, remove 등의 명령어 한 줄만 적으면 알아서 사이즈를 줄여준다.

근데 for문이 돌면서 찾아주는걸까?

 

 


요약

저장할 데이터 개수가 가변적일 때,

중간에 삽입과 삭제가 없을 때 사용 ( 범위 검사할 필요가 없기 때문에 v.at(i) 대신에 v[i]를 사용하였다. )

삽입과 삭제가 빈번할 때는 list나 deque를 사용하자.

#include <vector>
#include <iostream>
void swap(int i, int j, vector<int> &v) {
	int temp = v[i];
    v[i] = v[j];
    v[j] = temp;
}

void main() {
	vector<int> v(10, 0);		// 10 크기 할당, 모두 0으로 초기화			
	v.emplace(v.begin()+1, 1);	// 첫번째 인덱스에 1 추가
    							// [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    v.size();                   // size = 11, capacity는 환경에 따라 다름         
                                
    v.pop_back();				// [0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
    
    v.size();					// size = 10
    v.reserve(20);				// capacity = 20 ( 최대 할당 크기 )
    
    v.push_back(2);				// [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2]
    
    swap(1, 2, v);				// [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2]
    
    
    cout << v[0] << endl;		// 0
    
    cout << *(v.begin()) << endl;	// 0

    count << *(v.end()-1) << endl;	// 2
}

 

 

vector 선언 및 초기화

void main() {
	vector<int> vec1;			// 비어있는 vector 생성
    vec1.assign(10, 1);			// vec1의 10 크기(0~9)에 1로 초기화
    
    
    vector<int> vec2(10);		// 10개의 크기(capacity)를 할당 받음. 0으로 초기화
    vec2.assign(5, 10);			// vec2의 0~4까지 10으로 초기화
    
    
    vector<int> vec3(10, 3);	// 10개의 크기를 할당받음. 3으로 초기화
    
    
    vector<int> vec4 = {10, 10, 10, 5, 5, 4};	// 오른쪽의 변수로 초기화
    vector<int> vec5[] = {{1, 10}, {2, 5], {3, 4}};	// 2차원 배열 벡터. 행 가변, 열 고정


   	vector<int> vec6(v3); 		// vec3를 복사
}

 

 

vector 값 추가

void main() {
	vector<int> vec1;			// 비어있는 vector 생성
    
    vec1.push_back(10);			// 마지막에 추가 ( vec1[size++] = 10; )
								// [ 10 ]
                                
    vec1.insert(vec1.begin(), 2 )	// vec1의 0번째에 2를 추가, 복사생성자 호출
    								// [ 2, 10 ]
    
    vec1.insert(vec1.begin()+1, 3 ) // vec1의 1번째에 3을 추가
    								// [ 2, 3, 10 ]
                                    
    vec1.emplace(vec1.begin()+1, 4)	// vec1의 1번째에 4를 추가, 벡터 내부에서 값 생성
    								// [ 2, 4, 3, 10 ]
                                    
    vec1.emplace_back(5);			// vec1의 마지막에 5 추가
    								// [ 2, 4, 3, 10, 5 ]
    
}

※ insert와 emplace 차이   -> emplace 사용을 권장

insert는 모든 값들을 메모리에 복사한 후 값을 넣는다. (복사생성자 호출. array의 끼워넣기 -> 오버헤드, 성능 저하)

emplace는 벡터 내부에서 값을 생성 (템플릿 <T>에 대한 생성자만 호출)

 

vector 값 삭제

void main() {
	vector<int> vec1 = { 2, 4, 3, 10, 5 };
    
    vec1.pop_back();	// 맨 끝의 값 제거 ( vec1[size--] = null; }
    					// [ 2, 4, 3, 10 ]
    
    vec1.erase(v.begin())	// 0번째 값 제거, O(n) : 뒤에서 하나씩 당겨서 저장
    						// [ 4, 3, 10 ]
    
    vec1.erase(v.begin(), v.begin() + 2);	// 0번째부터 1번째 값 지우기 ( 총 두개)
    										// [ 10 ]
                                            
    vec1.clear();			// 모든 요소를 지운다. return size;( size = 0 , capacity = 5 )
    
    vector<int>().swap(vec1);	// 빈 vector(capacity=0)와 vec1를 바꾼다. 메모리 절약
    vec1.capacity();			// capacity = 0
}

 

 

 

vector 값 검색 - []를 추천

#include <iostream>
#include <vector>
#include <algorithm>

void main() {
	vector<int> v = { 0, 1, 2, 3, 4, 5 };
    
    v.at(1);			// 1 ( 범위 검사 o, 범위 밖일 경우 예외처리 발생 - std::out_of_range )
    v[1];				// 1 ( 범위 검사 x ), []를 권장
    v.front();			// 0
    v.back();			// 5
    
    for_each(v.begin(), v.end(), [&](int& n) {			// v.end()는 null값의 주소값, 마지막 값 출력하고 싶을 때 *(v.end()-1)로 해야함
    	cout << n << endl;				// 0, 1, 2, 3, 4, 5
    });
    
    for_each(v.rbegin(), v.rend(), [&](int& n) {				// reverse
    	cout << n << endl;				// 5, 4, 3, 2, 1, 0
    });
    
    
    /* iterator 이용 */
    vector<int>::iterator itor = v.begin();
 
    for (; itor != v.end(); itor++)
        cout << *itor << endl;        	// 0, 1, 2, 3, 4, 5
 
 
    vector<int>::reverse_iterator itor2 = v.rbegin();
 
    for (; itor2 != v.rend(); itor2++)
        cout << *itor2 << endl;        // 5, 4, 3, 2, 1, 0
}

 

 

vector 메모리 공간 관리

void main() {
	vector<int> v(10, 0);		// 10 크기 할당, 모두 0으로 초기화			
	
    v.size();                   // size = 10, capacity는 환경에 따라 다름         
                                
    v.reserve(20);				// capacity = 20 ( 할당 크기 지정 )
    
    v.capacity();				// 20, 할당된 공간 크기
    
    v.max_size();				// system에서 만들어질 수 있는 최대 크기 반환
    
    v.shrink_to_fit();			// 10, capacity = size; 남은 공간 없애줌
    
    vector<int>().swap(v);		// 빈 vector와 v를 교환. 메모리 절약 ( capacity = 0 )
}

※ size와 capacity   -> emplace 사용을 권장

size : 벡터가 생성된 크기 ( 값이 들어가있는 크기 )

capacity : 할당된 벡터의 공간 크기 ( 메모리에 차지하는 벡터의 크기 )

-> 벡터의 크기가 capacity를 초과하면 재할당(re-allocation) 발생 ( 성능 저하 )

-> 모든 값들을 새로운 메모리 공간에 복사한 후 기존 벡터 파괴

 

재할당을 줄이기 위해서 reserve()를 통해 capacity 크기를 설정하자. ( 너무 크게 잡을 경우 메모리 낭비 )

shrink_to_fit()를 통해 capacity=size 가능

 

clear()의 경우 값이 지워질 뿐 공간은 남아있다.(size == 0, capacity == 기존크기, 메모리 낭비 )

swap을 이용하여 메모리 free 해주자. ( 사실 함수가 끝나면 자동으로 힙에서 메모리 해제가 되니 특수한 경우에 사용. )

 

 

 

vector의 call by value ( 값에 의한 호출 -  get 가능, set 불가 )

void swap(int i, int j, vector<string> v ) {	// &로 vector를 받자 ( v가 array이다. )
	string temp = v[i];
    v[i] = v[j];
    v[j] = temp;
}

void main() {
	vector<string> vec1 = {... };
    ...
    swap(i, j, vec1);	// vec1의 i, j번째를 바꾸기. vec1의 주소값을 넘김(전체를 넘김)
    ...
}

 

vector의 call by reference ( 참조에 의한 호출 - get과 set 모두 가능 )

void swap(int i, int j, vector<string> &v ) {	// &로 vector를 받자 ( v가 array이다. )
	string temp = v[i];
    v[i] = v[j];
    v[j] = temp;
}

void main() {
	vector<string> vec1 = {... };
    ...
    swap(i, j, vec1);	// vec1의 i, j번째를 바꾸기. vec1의 주소값을 넘김(전체를 넘김)
    ...
}

 

 

 

 


참고 사이트

 

 blockdmask.tistory.com/70  

insert와 emplace 차이 : hwan-shell.tistory.com/119

 master-hun.tistory.com/70

 

 

call by reference : soyoonique.tistory.com/32