v1 벡터를 v2의 중간 이후의 요소로 만드는 가장 빠른 방법

assign은 표준 시퀀스 컨테이너(vector, string, deque, llist) 모두 사용 가능

v1.assign(v2.begin() + v2.size() / 2, v2.end());

 

삽입 연산자(inserter, back_inserter, front_inserter 등)를 사용해서 복사 대상 범위를 지정하는 copy는 멤버 함수로 변경하는 것이 가능

copy의 경우 복사에 초점이 맞추어져 있지만 insert를 통해 삽입의 의미를 명확하게 나타낼 수 있음

v1.insert(v1.end(), v2.begin() + v2.size() / 2, v2.end());

 

단일 요소 멤버 함수보다 범위 멤버 함수가 더 좋은 이유

코드가 대개 짧아 작성하기 쉽고, 명확하고 간결한 의미를 전달하여 이해하기 쉬워 유지보수성이 올라감

 

불필요한 연산/복사 방지

인덱스가 증가하는 연산

반복자를 계속 할당하는 이유는 삽입하면 반복자가 무효화되고, 만약 무효화되지 않아도 매번 벡터의 앞에 추가되는 것을 방지하기 위함

// 단일 멤버 함수
vector<int>::iterator insertLoc(v.begin());
for (int index = 0; index < numValues; ++index)
{
	insertLoc = v.insert(insertLoc, data[index]);
}

// 범위 멤버 함수
v.insert(v.end(), data.begin(), data.end());

 

불필요한 함수 호출 방지

insert가 numValue번 호출되고, insert는 1번 호출되므로 numValue-1만큼 줄어듦

만약 인라인된다면 호출 횟수는 감소하지만 코드 크기 증가

 

불필요한 이동 방지

맨 뒤에 삽입하는 경우가 아니므로 삽입할 때마다 numValue번 n 개의 요소들이 이동해야 하는 것을 방지 ( n * numValue 이동 감소)

복사나 이동 비용이 큰 객체를 담고 있다면 비용이 더 증가하는 것을 방지

범위 멤버 함수를 사용한다면 마지막 위치까지 바로 옮기므로 n번의 이동 횟수뿐

  • 단 반복자 사이의 거리를 알 수 있어야 하는데, 순방향 반복자를 지원하지 않는 입출력 반복자(istream_iterator 등)를 제외하면 모두 가능

 

불필요한 메모리 할당 및 해제 방지

iterator와 인덱스를 가리키는 int 변수 생성 및 해제

메모리가 꽉 찰때마다 capacity를 두 배 늘리는 과정에서 새 메모리 할당 및 이동/복사 및 기존 메모리 해제가 일어나므로 log(numValue)번의 메모리 할당 방지

범위 멤버 함수는 필요한 메모리량을 예측할 수 있기 때문에 한 번만 메모리 할당이 발생

 

위의 내용은 vector에 관한 것으로, string도 동일

deque는 다른 메모리 관리 방식을 취하므로 불필요한 메모리 할당 및 해제 방지 내용은 해당하지 않음

list는 노드 기반으로 동작하므로 불필요한 메모리 할당 및 해제 방지 내용은 해당하지 않지만 새로운 문제 방지

삽입되는 위치 다음의 노드를 A라고 할 때, 삽입되는 노드의 next 포인터는 A를 가리키다 삽입되는 노드를 가리키고, A의 prev는 삽입되는 노드를 가리키므로 2 * (numValues - 1)번의 불필요한 연산 방지

 

위의 내용은 insert 함수 효율 분석으로 erase도 비슷하지만 erase는 요소 수가 줄어들 때 자동으로 메모리를 해제하지 않음

 

범위 멤버 함수

InputIterator는 어떤 입력 반복자도 받아들일 수 있는 타입

 

모든 표준 컨테이너는 범위로 생성할 수 있는 생성자가 있음

container::container(InputIterator begin, InputIterator end);

 

모든 표준 컨테이너는 범위로 삽입할 수 있는 멤버 함수가 있음

// 시퀀스 컨테이너
void container::insert(iterator position, InputIterator begin, InputIterator end);

// 연관 컨테이너(위치는 알아서 정함)
void container::insert(InputIterator begin, InputIterator end);

 

모든 표준 컨테이너는 범위로 삭제할 수 있는 멤버 함수가 있음

iterator container::erase(iterator begin, iterator end);

 

모든 표준 시퀀스 컨테이너는 범위 할당 멤버 함수가 있음

void container::assign(InputIterator begin, InputIterator end);

+ Recent posts

목차