2010-07-31 3 views
3

STL 컨테이너를 어떻게 복사합니까?C++ : 컨테이너를 효율적으로 복사하십시오.

// big containers of POD 
container_type<pod_type> source; 
container_type<pod_type> destination 

// case 1 
destination = source; 

// case 2 
destination.assign(source.begin(), source.end()); 

// case 3 assumes that destination.size() >= source.size() 
copy(source.begin(), source.end(), destination.size()); 

가능한 경우 사례 1을 사용합니다. 케이스 2는 다른 유형의 컨테이너 용입니다. 사례 3은 대상이 원본보다 크고 나머지 요소를 유지하려는 경우에 필요합니다.

그러나 건설/파괴 비용이 0이 아닌 비 POD 요소는 어떻습니까? 케이스 3이 케이스 2보다 좋을까요? 목적지가 소스보다 큰 경우, 구현은 예기치 않은 일을 할 수 있습니다. Visual Studio 2008이 경우 2에서 수행하는 작업입니다.

  1. 대상의 모든 요소가 삭제됩니다.
  2. 그런 다음 복사 생성자가 대상의 크기만큼 호출됩니다. 왜?
  3. 소스의 모든 요소는 대상의 해당 요소에 할당됩니다.
  4. 대상의 추가 요소가 삭제됩니다.

GCC 4.5가 더 좋습니다. 소스의 모든 요소는 할당을 통해 복사 된 다음 대상의 추가 요소가 삭제됩니다. case3을 사용하여 크기가 인 경우 두 플랫폼 모두에서 동일한 작업을 수행합니다 (크기가 인 기본 생성자 하나만 제외). 제가 의미하는 바를 보여주는 장난감 프로그램이 있습니다.

#include <iostream> 
#include <vector> 
#include <list> 
#include <algorithm> 
using namespace std; 

struct A { 
    A() { cout << "A()\n"; } 
    A(const A&) { cout << "A(const A&)\n"; } 
    A& operator=(const A&) { 
     cout << "operator=\n"; 
     return *this; 
    } 
    ~A() { cout << "~A()\n"; } 
}; 

int main() { 
    list<A> source(2); 
    vector<A> desrination1(3); 
    vector<A> desrination2(3); 

    cout << "Use assign method\n"; 
    desrination1.assign(source.begin(), source.end()); 

    cout << "Use copy algorithm\n"; 
    copy(source.begin(), source.end(), desrination2.begin()); 
    desrination2.resize(2); 

    cout << "The End" << endl; 
    return 0; 
} 
+2

무엇이 문제입니까? – onof

+3

나는 거의 자신의 코드로 컨테이너를 복사하지 않는다. (그렇게해야 할 것 같지 않다.) 그래서 나는 결코 그 문제를 결코 고려하지 않았다. –

+0

@onof STL 컨테이너는 어떻게 복사합니까? – user401947

답변

4

대상의 모든 요소는 입니다. 그런 다음 복사 생성자 이 대상 크기만큼 여러 번 호출됩니다. 왜?

당신이 말하는 바가 확실하지 않습니다. 거의 같은 일을해야

assert(source.size() <= destination.size()); 
destination.erase(copy(source.begin(), source.end(), destination.begin()), destination.end()); 

:와

template<class Iterator> 
void assign(Iterator first, Iterator last) 
{ 
     erase(begin(), end()); // Calls the destructor for each item 
     insert(begin(), first, last); // Will not call destructor since it should use placemenet new 
} 

당신이 뭔가를 할 것입니다 복사 지정은 일반적으로 뭔가를 구현됩니다. 나는 소스가 대상 (맞는/삽입 컨테이너의 용량을 확인해야하기 때문에 조금 빨리)에 적합하다는 것을 알고 있다면 사본을 사용할 것입니다. 그렇지 않으면 가장 간단한 이후에 assign을 사용할 것입니다. 또한 copy를 사용하고 대상이 너무 작 으면 resize()를 호출하면 resize()가 덮어 쓸 모든 요소를 ​​구성하므로 비효율적입니다.

GCC 4.5가 더 좋습니다.소스의 모든 요소 은 지정을 통해 복사 된 다음 대상의 여분의 요소 이 삭제됩니다. 케이스 3을 사용하여 크기를 조정 한 후 두 플랫폼 모두에서 동일 함 ( 크기 조정이 필요한 기본 생성자 제외). 다음은 장난감 프로그램 으로 내 뜻을 보여줍니다.

동일한 내용입니다. 할당은 복사 생성 측면에서 구현됩니다.

class A 
{ 
    A& operator=(A other) 
    { 
     std::swap(*this, other); 
     return *this; 
    } 

    // Same thing but a bit more clear 
    A& operator=(const A& other) 
    { 
     A temp(other); // copy assignment 
     std::swap(*this, temp); 
     return *this; 
    } 
} 
+0

Visual Studio에서 코드를 실행하고 직접 확인하십시오. – user401947

+0

내가 뭘 볼 수 있니? 제발 당신이 틀린 부분이라고 생각하는 부분에 좀 더 자세하게 말하십시오. – ronag

0

전체 컨테이너를 복사하는 경우 컨테이너 복사 생성자 또는 할당 연산자를 사용해야합니다. 그러나 컨테이너 내용 만 복사하면 std::copy을 사용하는 것이 가장 좋습니다. POD 개체 이상을 사용하는 경우 각 인스턴스에 대해 복사 생성자 호출을 저장할 수 없습니다.

공유/스마트 포인터를 사용할 것을 고려해야합니다.이 포인터는 복사시 참조 카운터를 증가시키고 인스턴스를 수정할 때 copy on write를 사용합니다.

+3

나는'std :: copy'가 * 할당 *에 대해'constainer :: assign'보다 낫다는 것에 동의하지 않습니다. 'copy'를 사용하면 소스의 크기에 맞게 컨테이너의 크기를 수동으로 설정하거나'clear()'하고 삽입 반복자를 사용해야합니다. 첫 번째 경우 대상이 소스보다 큰 경우 기본 초기화를 만들어야합니다 (포함 된 요소가 기본 생성자를 구현할 필요가없는 경우에도 가능). 나중에 다시 작성해야합니다. 두 번째 경우에는 컨테이너를 지운 후에 다시 할당하기 위해 여러 할당이 필요할 수 있습니다. –

+1

'assign'의 경우 일반적으로 더 많은 정보를 사용할 수 있습니다 : 구현은 컨테이너 타입, 요소의 수를 알고 있습니다 - 반복자가 무작위 반복자 인 경우 - 그것이 커질 필요가 있다면 컨테이너의 초기 상태입니다. 그 정보는 이용 가능하지 않거나'std :: copy'에서 소스 크기의 경우에 유용하게 사용할 수 없습니다. –

관련 문제