2017-02-04 10 views
4

벡터 공간을 일부 예약 한 다음 std::copy_n()으로 일부 값을 복사하면 올바르게 복사되고 액세스 할 수 있지만 벡터 크기는 다음과 같습니다. 여전히 0입니다. 이것은 예상 된 행동입니까? 효율적이지 않은 경우에도 벡터의 크기를 조정해야합니까?std :: copy_n은 대상 벡터 크기를 변경하지 않습니다

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

int main() 
{ 
    std::vector<double> src, dest; 

    for(double x = 0.0; x < 100.0; ++x) 
     src.push_back(x); 

    dest.reserve(src.size()); 

    std::copy_n(src.cbegin(), src.size(), dest.begin()); 

    std::cout << "src.size() = " << src.size() << std::endl; 
    std::cout << "dest.size() = " << dest.size() << std::endl; 

    for(size_t i = 0; i < src.size(); ++i) 
     std::cout << dest[i] << " "; 

} 

컴파일러 테스트 : 그 소리, GCC, 비주얼 C++

+0

'reserve()'는 용량이 아니라 크기에만 영향을 미친다고 생각합니다. –

+0

@RawN, 네,하지만'copy_n'이 크기를 업데이트 할 것을 기대했습니다. – Pietro

+0

당신은 단순히 dest = src를 할 수 있다는 것을 알고 있습니까? vector의 assign 함수를 아십니까? –

답변

5

을하지만 벡터의 크기는 여전히 제로

std::copy_n 단지 복사, 컨테이너의 크기를 변경하지 않습니다 iterators의 값과 단계; 그것은 심지어 컨테이너에 관한 어떠한 정보도 가지고 있지 않습니다. 그래서 코드는 정의되지 않은 동작을합니다. 심지어 잘 작동하는 것 같습니다.

효율적이지 않더라도 벡터의 크기를 조정해야합니까?

예, std::vector::reserve 대신 std::vector::resize을 사용하여 문제를 해결할 수 있습니다. 생각한 것처럼 모든 요소가 resize에 의해 구성되고 copy_n에 의해 할당됩니다.

std::back_inserter을 사용할 수 있습니다. std::back_inserter은 컨테이너의 push_back() 멤버 함수 (즉, 구성 요소를 직접 작성)를 호출하여 컨테이너 끝에 요소를 추가하므로 컨테이너 크기가 커집니다. 예 :

dest.reserve(src.size()); 
std::copy_n(src.cbegin(), src.size(), std::back_inserter(dest)); 
+0

'std :: back_inserter' 방식이'std :: vetor :: resize'보다 느리지 않고 복사가되지 않습니까? –

+0

@KamilKoczurek No. 컨테이너의'push_back'을 호출하여 요소를 직접 추가합니다. 'resize'로 모든 요소를 ​​구성한 다음 할당하십시오. – songyuanyao

+0

맞아, 나는'std :: vetor :: reserve'를 호출한다는 것을 몰랐다. 그래서 메모리를 다시 할당 할 필요가 없다. –

0

성병 : : 벡터는 크기용량 있습니다. 삽입 속도를 높이는 데 필요한 공간보다 더 많은 공간을 확보합니다. 예약은 해당 용량을 지정할 수있게하며 크기는으로 변경되어 실제 벡터 크기를 변경합니다.

0

reserve을 호출 한 후 dest을 호출했지만 요소를 저장할 메모리가 할당되었지만 생성자를 호출하지 않고 실제로 비어 있으므로 코드가 UB로 연결됩니다. resize을 사용하여 실제로 이러한 요소를 만든 다음 괜찮습니다.

dest.resize(src.size()); 
std::copy_n(src.cbegin(), src.size(), dest.begin()); 

std::cout << "src.size() = " << src.size() << std::endl; 
std::cout << "dest.size() = " << dest.size() << std::endl; 

for(size_t i = 0; i < src.size(); ++i) 
    std::cout << dest[i] << " "; 
2

표준 라이브러리 알고리즘에 대해 기억해야 할 중요한 것은 그들이 범위이 아닌 컨테이너에서 작동한다는 것입니다. 컨테이너는 범위를 만들 수있는 방법 중 하나이지만 유일한 방법은 아닙니다. 결과를 범위에 쓰는 알고리즘은 유효한 위치에 쓰고 있다고 가정합니다. 그들은 글을 쓰고있는 범위를 넓히거나 확장 할 수 없다.

std::copy_n으로 전화 할 때는 결과를 저장할 수있을만큼 큰 범위를 제공해야합니다. 이는 dest.reserve(std.size());으로 메모리를 할당하는 것뿐만 아니라 dest.resize(src.size());으로 범위를 설정한다는 의미입니다.

dest.begin() 대신 std::back_inserter(dest)의 알고리즘을 호출하여 컨테이너에 첨부되어 있고 크기를 조정해야하는 범위를 제공 할 수도 있습니다.