본문 바로가기
C,C++/C++

[C++] 컨테이너 복사 std::copy 함수, 반복자 어댑터 std::back_inserter

by woohyeon 2019. 10. 26.
반응형

안녕하세요.

오늘은 컨테이너 타입에 관계없이 특정 범위의 요소를 복사하여 컨테이너의 특정 위치에 추가할 수 있는 copy 함수와 함께 자주 사용되는 반복자 어댑터 back_inserter 함수에 대해 알아보겠습니다.


Header:  <algorithm>

template <class InputIterator, class OutputIterator>
OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result);

: [first, last) 범위의 모든 요소를 result가 가리키는 위치부터 순차적으로 복사합니다. 
이때, result가 가리키는 위치의 저장 공간은 충분하다고 가정합니다. copy 함수가 공간을 확보해주지 않습니다. 
요소 저장은 내부적으로 '=' 연산, 즉 대입을 통해 저장되기 때문에 push_back처럼 자동으로 크기를 늘려주며 요소를 저장하지 않습니다. 따라서 요소를 저장할 수 있는 공간이 없다면 런타임 에러가 발생하게 됩니다. 이 문제의 해결책 중 하나로 잠시 후 살펴볼 back_inserter 함수와 함께 자주 사용합니다. 함수 종료 시 result를 반환합니다.



Header: <iterator>

template <class Container>
back_insert_iterator<Container>  back_inserter (Container& x);

:  컨테이너를 받아 back_insert_iterator 타입의 객체를 생성하여 반환합니다. 
back_insert_iterator 타입은 일종의 반복자 클래스로, push_back 함수처럼 컨테이너의 끝에 쉽게 삽입을 할 수 있도록 도와줍니다. 해당 타입은 요소를 복사 또는 이동할 목적지를 가리키는 반복자로 사용할 때 용이합니다. 예를 들어
내부적으로 '=' 연산을 사용하여 목적지에 요소를 저장하는 std::copy 또는 std::transform과 같은 함수를 사용할 경우 컨테이너의 잔여 공간을 신경 써줘야 하는 불편함이 있습니다. 즉, 위에서 살펴본 copy의 output 인자로 back_insert_iterator 타입이 아닌 기본 반복자(begin, end)를 사용한다면  잔여 공간이 충분치 않을 경우 런타임 에러가 납니다. 하지만 back_insert_iterator 타입의 객체는 '=' 연산을 통해 요소에 값을 저장하더라도 내부적으로 push_back을 호출하도록 오버 로딩되어 있습니다. 따라서 저장 공간을 프로그래머가 신경 쓸 필요가 없습니다.

back_insert_iterator 클래스와 transform 함수에 대한 더 자세한 내용은
다음 포스팅을 참고해주세요!
2019/11/04 - [C++/Function] - [C++ STL] std::transform() 함수 사용법 / back_insert_iterator

 


How to work)

copy(begin, end, out);

/* 
    위 코드는 [begin, end) 범위의 모든 요소를 
    out이 가리키는 위치부터 순차적으로 복사합니다.
    
    위 코드는 아래 코드와 같은 방식으로 동작합니다.
*/

while(begin != end)
{
    *out = *begin;
    ++out;
    ++begin;
}

 

Example)

#include <iostream>
#include <algorithm> // std::copy
#include <iterator>  // std::back_inserter
#include <vector>

int main(void)
{
    std::vector<int> foo { 1, 2, 3, 4, 5 };
    std::vector<int> bar { 10, 20, 30, 40, 50 };

	// foo 뒤에 순차적으로 bar의 요소들을 copy합니다.
	std::copy(bar.begin(), bar.end(), std::back_inserter(foo));

	for (const int val : foo)
	{
		std::cout << val << " ";
	}

	std::cout << "\n";

	return 0;
}

 


Explain)

std::copy(bar.begin(), bar.end(), std::back_inserter(foo));

컨테이너 bar의 처음부터 마지막 범위 (=모든) 요소를 컨테이너 foo의 마지막 요소의 다음 위치부터 순차적으로 복사하며 확장합니다.

Output)

 

참고)

http://www.cplusplus.com/reference/algorithm/copy/

http://www.cplusplus.com/reference/iterator/back_inserter/




댓글