C ++, 복사가 벡터로 설정


146

나는 복사해야합니다 std::setstd::vector:

std::set <double> input;
input.insert(5);
input.insert(6);

std::vector <double> output;
std::copy(input.begin(), input.end(), output.begin()); //Error: Vector iterator not dereferencable

문제는 어디에 있습니까?


5
assign()기능 도 있습니다 :output.assign(input.begin(), input.end());
유전자 Bushuyev

당신의 벡터는 비어 있습니다. 사람들이 아래에서 지적하고 있지만 여러 가지 방법으로 해결할 수 있습니다.
AJG85

@Gene : assign ()은 필요한 양의 저장 공간을 미리 예약 ()하려고합니다. 반복자가 엄격하게 InputIterator가 아닌 한 입력 반복자를 사용하여 필요한 양을 결정합니다.이 경우 예약을 건너 뛰고 모든 push_back ()에서 재 할당이 발생합니다. 스펙트럼의 반대쪽 끝에서 BiderectionalIterators는 끝을 시작에서 빼는 것을 허용합니다. 그러나 std :: set의 반복자는 둘 다 (ForitIterator는 아닙니다) 불행한 일입니다.이 경우 assign ()은 전체 세트를 걸어 크기를 결정합니다. 큰 세트의 성능이 좋지 않습니다.
Sergey Shevchenko

답변:


213

당신은 사용해야합니다 back_inserter:

std::copy(input.begin(), input.end(), std::back_inserter(output));

std::copy삽입하는 컨테이너에 요소를 추가하지 않습니다. 컨테이너에는 반복자가 있습니다. 이 때문에 출력 반복자를 직접로 전달하는 경우 std::copy입력 범위를 보유하기에 충분한 범위를 가리키는 지 확인해야합니다.

std::back_inserterpush_back각 요소의 컨테이너를 호출하는 출력 반복자를 작성하여 각 요소가 컨테이너에 삽입됩니다. 또는 std::vector복사 할 범위를 보유 하기에 충분한 수의 요소를 만들 수도 있습니다 .

std::vector<double> output(input.size());
std::copy(input.begin(), input.end(), output.begin());

또는 std::vector범위 생성자를 사용할 수 있습니다 .

std::vector<double> output(input.begin(), input.end()); 

3
안녕 제임스, std :: copy 줄 (응답의 첫 번째 코드 블록) output.insert(output.end(), input.begin(), input.end());대신 대신 할 수 없었 습니까?
user2015453

아니면 그냥 cbegin 및 cend 버전을 사용하십시오. output.insert(output.cend(), input.cbegin(), input.cend());어떻게 생각하십니까? 감사.
user2015453

2
출력해야합니까? reserve (input.size ()); 혼자서 또는 일부 컴파일러가 나를 위해 그것을 희망 할 수 있습니까?
jimifiki

@ jimifiki, 내가 두려워하지 않기를 바랍니다.
Alexis Wilke

첫 번째 벡터 초기화가 잘못되었습니다. input,size()빈 항목 의 배열을 만든 다음 그 뒤에 추가를 추가합니다. 나는 당신이 사용하는 것을 의미한다고 생각합니다 std::vector<double> output; output.reserve(input.size()); std::copy(...);.
Alexis Wilke

121

반복자를 취하는 벡터의 생성자를 사용하십시오.

std::set<T> s;

//...

std::vector v( s.begin(), s.end() );

v에서 s의 내용을 원하고 v에 데이터를 복사하기 전에 v에 아무것도 없다고 가정합니다.


42

다음을 사용하는 또 다른 대안이 있습니다 vector::assign.

theVector.assign(theSet.begin(), theSet.end());

24

벡터 객체에 세트의 내용을 담을 공간이 충분하지 않습니다.

std::vector<double> output(input.size());
std::copy(input.begin(), input.end(), output.begin());

1
이것은 -1을받을 자격이 없습니다. 특히, 이것은 벡터가 하나의 할당만을 수행 할 수있게한다 (O (1)에서 집합 반복기의 거리를 결정할 수 없기 때문에). 사본이 memcpy로 끓일 수 있도록 가치가 있습니다. 구현이 벡터의 ctor에서 루프를 제거 할 수 있다고 계산하면 후자는 여전히 가치가 있습니다. 물론 전자는 예약을 통해 달성 할 수도 있습니다.
Fred Nurk

모르겠어요 도와 드리겠습니다.
wilhelmtell

나는 당신에게 -1을 주었지만 그것은 내 생각입니다. 투표를 취소 할 수 있도록 약간만 수정하면 +1을 드리겠습니다. 이는 우선 실패 속성으로 인해 실제로 매우 깨끗한 솔루션입니다.
Fred Foo

나는 답을 직접 편집하면 공감대를 할 수 있다는 것을 알았습니다. 그렇게한다면, 첫 번째 메모리 할당에 +1을주었습니다. 죄송합니다!
Fred Foo

3

가장 효율적인 방법은 요소를 미리 할당 한 다음 배치하는 것입니다.

template <typename T>
std::vector<T> VectorFromSet(const std::set<T>& from)
{
    std::vector<T> to;
    to.reserve(from.size());

    for (auto const& value : from)
        to.emplace_back(value);

    return to;
}

이렇게하면 기본 생성자를 먼저 호출하는 대신 위에 나열된 다른 솔루션에 대한 할당 할당 연산자를 사용하는 대신 모든 요소에 대해 복사 생성자를 호출합니다. 아래에 더 많은 설명이 있습니다.

  1. back_inserter를 사용할 수 있지만 벡터 ( https://en.cppreference.com/w/cpp/iterator/back_insert_iterator ) 에서 push_back ()을 호출 합니다. emplace_back ()push_back ()을 사용할 때 임시 작성을 피하기 때문에 더 효율적 입니다. 사소하게 구성된 유형에는 문제가되지 않지만 사소하게 구성되지 않은 유형 (예 : std :: string)에 성능 영향을 미칩니다.

  2. size 인수로 벡터를 구성하면 모든 요소가 기본적으로 생성됩니다 (아무것도하지 않음). 예를 들어 std :: copy ()를 사용하는 솔루션과 같습니다 .

  3. 마지막으로 vector :: assign () 메소드 또는 반복자 범위를 취하는 생성자는 세트 반복자 에서 std :: distance () (요소 수를 알기 위해)를 호출하기 때문에 좋은 옵션이 아닙니다 . 세트가 이진 검색 트리 데이터 구조이고 랜덤 액세스 반복자를 구현하지 않기 때문에 모든 세트 요소를 통해 원치 않는 추가 반복이 발생 합니다.

희망이 도움이됩니다.


왜 이것이 빠른지, 왜 이것을 back_inserter사용할 필요 가 없는지에 대한 권위에 대한 참조를 추가하십시오
Tarick Welling

답변에 더 많은 설명이 추가되었습니다.
dshvets1

1

std::copy빈 용기에 넣을 수 없습니다. 그렇게하려면 다음과 같이 insert_iterator를 사용해야합니다.

std::set<double> input;
input.insert(5);
input.insert(6);

std::vector<double> output;
std::copy(input.begin(), input.end(), inserter(output, output.begin())); 

3
벡터가 처음으로 재 할당 될 때 실패합니다. output.begin ()의 반복자가 무효화됩니다.
Fred Nurk
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.