HOWTO · C++
C++에서 벡터 컨테이너 객체 복사
이 기사에서는 C++에서 벡터 컨테이너 객체를 복사하는 방법을 보여줍니다.
이 페이지의 내용
C++ std::vector를 복사하려면 새 벡터를 만들 때 복사 생성자를 사용하고, 이미 있는 벡터의 내용을 바꿀 때는 복사 대입을 사용합니다. 선택한 범위만 복사하려면 범위 생성자를 사용하면 됩니다. std::copy는 대상 범위에 충분한 요소가 이미 있을 때 사용할 수 있고, std::back_inserter는 대상 벡터 끝에 요소를 추가합니다. 이러한 연산은 요소의 형식에 따른 복사를 수행하며, 포인터가 가리키는 객체까지 재귀적으로 복사하지는 않습니다.
복사 생성자 또는 대입 연산자로 벡터 복사하기
복사 초기화는 기존 벡터를 바탕으로 새 벡터를 만듭니다. std::vector<int> copy = source;처럼 작성할 수 있습니다. 괄호를 사용하는 직접 초기화도 같은 일을 합니다: std::vector<int> copy(source);. 대상 벡터가 이미 있다면 대입을 사용합니다: destination = source;. 대입하면 대상 벡터의 요소가 교체됩니다. 이 형식들을 사용하려면 <vector>를 포함하세요.
다음 예제를 실행해 보세요:
이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.
#include <cstddef>
#include <iostream>
#include <vector>
int main() {
const std::vector<int> source{2, 4, 6};
std::vector<int> copy = source;
std::vector<int> destination{9};
destination = source;
for (std::size_t i = 0; i < copy.size(); ++i) {
if (i != 0) {
std::cout << ' ';
}
std::cout << copy[i];
}
std::cout << '\n';
for (std::size_t i = 0; i < destination.size(); ++i) {
if (i != 0) {
std::cout << ' ';
}
std::cout << destination[i];
}
std::cout << '\n';
}
2 4 6
2 4 6
이 프로그램은 복사된 각 벡터를 한 줄씩 출력합니다. std::vector<int>의 요소는 값이므로, 한 벡터의 정수를 바꾸어도 다른 벡터의 해당 정수는 바뀌지 않습니다.
벡터의 범위 생성자로 범위 복사하기
범위 생성자에는 반열린 반복자 범위를 전달합니다. 첫 번째 반복자가 가리키는 요소는 포함하고, 두 번째 반복자가 가리키는 요소는 포함하지 않습니다. 이 생성자를 초기화 목록 문법과 구분하려면 괄호를 사용하세요.
std::vector<int> copy(source.begin(), source.end());는 전체 범위를 복사합니다. 하위 범위를 복사하려면 원하는 요소를 가리키는 반복자일 때 std::vector<int> middle(source.begin() + 1, source.end() - 1);처럼 작성할 수 있습니다.
첫 번째 선언은 모든 요소를 복사하고, 두 번째 선언은 이 예제에서 양 끝을 제외한 내부 범위를 복사합니다. 두 반복자는 모두 같은 원본 벡터 안의 유효한 범위를 가리켜야 합니다. 새 대상 벡터가 필요할 때 전체 벡터나 일부 범위를 복사하기에 편리한 방법입니다.
std::copy로 범위 복사하기
std::copy는 이미 존재하는 대상 범위에 요소를 씁니다. <algorithm>을 포함하고, 복사하기 전에 대상에 원본 범위의 요소 수만큼 공간이 있는지 확인하세요. 이 알고리즘만으로 벡터의 크기가 늘어나지는 않습니다.
std::vector<int> destination(source.size());로 대상 범위를 준비한 다음 std::copy(source.begin(), source.end(), destination.begin());을 호출하면 원본에 필요한 만큼의 대상 요소가 마련됩니다.
일부 범위만 복사하려면 그 범위의 시작 반복자와 끝 반복자를 전달하고, 대상에도 해당 범위를 담을 만큼 요소를 준비하세요. 원본 범위와 대상 범위가 알고리즘의 요구사항을 위반하는 방식으로 겹치지 않아야 합니다.
std::back_inserter로 복사한 요소 추가하기
요소를 추가하면서 필요에 따라 벡터가 커지도록 하려면 <algorithm>과 <iterator>를 포함하고 std::back_inserter를 사용하세요.
예를 들어 std::vector<int> destination{10};을 선언한 뒤 std::copy(source.begin(), source.end(), std::back_inserter(destination));를 호출하면 원본의 요소가 대상 끝에 추가됩니다.
기존의 10은 맨 앞에 남고, 그 뒤에 원본의 값이 이어집니다. 대상에 이미 요소가 있거나 최종 크기를 미리 정하지 않을 때 유용한 방식입니다.
반복문과 push_back으로 요소 복사하기
반복문을 사용하면 요소마다 수행하는 작업을 명시적으로 표현할 수 있습니다. push_back은 복사한 값을 끝에 추가하므로 기존 대상 벡터의 뒤에 요소가 이어집니다.
std::vector<int> destination;을 선언한 다음 다음처럼 반복하면 됩니다: for (const int& value : source) { destination.push_back(value); }.
일반적인 복사에는 벡터 복사 생성자나 범위 생성자가 대개 더 명확합니다. 요소를 추가하면서 각각 변환하거나 필터링해야 한다면 반복문이 적합합니다. 반복문에서도 표준 벡터 연산과 마찬가지로 각 요소의 형식에 따른 복사가 이루어집니다.
assign과 insert로 대상 요소 교체하거나 삽입하기
대상 벡터를 범위의 내용으로 교체하려면 assign(first, last)를 사용하세요. 대상의 나머지 요소는 유지하면서 원본 범위를 특정 위치에 넣으려면 insert(position, first, last)를 사용합니다.
내용을 교체할 때는 destination.assign(source.begin(), source.end());를 사용합니다. 원본 범위를 맨 앞에 삽입하려면 destination.insert(destination.begin(), source.begin(), source.end());를 사용하세요.
삽입 위치는 대상 벡터 안의 유효한 반복자여야 합니다. 삽입으로 벡터 저장 공간이 재할당되면 요소를 가리키던 모든 반복자, 포인터, 참조가 무효화됩니다. 재할당이 없더라도 삽입 위치 또는 그 뒤의 반복자와 참조는 무효화되지만, 그 앞의 것은 유효합니다. 삽입 후에는 영향을 받은 반복자와 참조를 다시 가져오세요.
벡터 복사에서 실제로 복사되는 것
std::vector는 요소를 연속된 메모리에 저장하고 그 저장 공간을 소유합니다. 벡터를 복사하면 별도의 벡터가 만들어지고, 그 안에 요소의 복사본이 들어갑니다. std::vector<int>에서는 정수 값이 복사되므로, 나중에 한 벡터의 요소에 값을 대입해도 다른 벡터의 값은 바뀌지 않습니다.
다른 요소 형식의 복사 동작은 해당 형식의 복사 연산을 따릅니다. 예를 들어 원시 포인터를 담은 벡터를 복사하면 포인터 값이 복사될 뿐, 포인터가 가리키는 객체가 새로 만들어지지는 않습니다. 요소가 스마트 포인터라면 std::shared_ptr의 공유 소유권처럼 해당 스마트 포인터의 의미에 따라 복사됩니다. 따라서 별도의 벡터라고 해서 요소가 가리키는 객체까지 항상 서로 독립적인 것은 아닙니다.
벡터 복사 방법 선택하기
새 벡터를 만들려면 복사 생성자나 범위 생성자를 선택하세요. 기존 대상의 내용을 교체하려면 복사 대입이나 assign을 사용합니다. 범위를 특정 위치에 추가하려면 insert를, 대상 벡터를 늘리면서 끝에 추가하려면 std::copy와 std::back_inserter를 함께 사용하세요. 이미 크기가 정해진 요소 범위에 쓰려면 크기를 준비한 대상과 std::copy를 사용하면 됩니다. 복사하면서 요소마다 별도 작업을 해야 한다면 push_back을 사용하는 반복문이 유용합니다.
벡터 전체를 새로 복사할 때는 복사 생성자를 우선 고려하고, 일부 요소만 복사할 때는 범위 생성자를 사용하세요. 기존 벡터에서는 내용을 교체할지, 특정 위치에 요소를 넣을지, 끝에 추가할지에 따라 대입 또는 assign, insert, std::back_inserter 중에서 고르면 됩니다.