2017-12-03 26 views
1

나는 벡터에 객체를 push_back() 할 때마다 벡터의 모든 기존 객체가 "재창조 된"것처럼 보였다.벡터가 push_back()에서 모든 객체를 다시 생성합니까?

이것을 테스트하기 위해 아래 테스트 프로그램을 만들었습니다. 프로그램이 수행하는 작업은 MyClass의 일부 인스턴스를 벡터에 push_back()하고 각 push_back() 후에 벡터에있는 현재 객체의 주소를 인쇄하는 것입니다. 생성자와 소멸자는 인스턴스가 작성/삭제 될 때마다 객체의 주소가있는 메시지를 인쇄합니다.

#include "stdafx.h" 
#include <vector> 
#include <iostream> 

using namespace std; 

class MyClass { 

public: 
    MyClass() { 
     cout << "Constructor: " << this << endl; 
    } 
    ~MyClass() { 
     cout << "Destructor: " << this << endl; 
    } 

}; 

void printAdresses(const vector<MyClass> & v) { 
    for (int i = 0; i < v.size(); i++) { 
     cout << &v[i] << endl; 
    } 
} 

int main() 
{ 
    vector<MyClass> v; 

    for (int i = 0; i < 4; i++) { 
     v.push_back(MyClass()); 
     cout << "Contains objects: " << endl; 
     printAdresses(v); 
     cout << endl; 
    } 

    system("pause"); 
    return 0; 
} 

아래의 내용은 프로그램 실행 결과입니다. 모든 블록은 루프의 한 반복에서 출력됩니다. 와 push_back()에 대한 인수로 주어진 항목의 생성자와 소멸자에서

Constructor: 00EFF6AF 
Destructor: 00EFF6AF 
Contains objects: 
034425A8 

Constructor: 00EFF6AF 
Destructor: 034425A8 
Destructor: 00EFF6AF 
Contains objects: 
034426F8 
034426F9 

Constructor: 00EFF6AF 
Destructor: 034426F8 
Destructor: 034426F9 
Destructor: 00EFF6AF 
Contains objects: 
034424E8 
034424E9 
034424EA 

Constructor: 00EFF6AF 
Destructor: 034424E8 
Destructor: 034424E9 
Destructor: 034424EA 
Destructor: 00EFF6AF 
Contains objects: 
034423F8 
034423F9 
034423FA 
034423FB 

아파트는 다른 개체의 소멸자가와 push_back() (하지만 해당 생성자?) 동안이라고합니다. 주소를 면밀히 살펴보면 소멸자가 push_back() 이전의 벡터에있는 요소에 속한다는 것을 알 수 있습니다. 그 후에 벡터에는 주소가 다르지만 요소 수가 동일하고 새로 push_backed 된 다른 객체가 포함됩니다.

이 모든 내용은 벡터의 모든 객체가 각각의 push_back 후에 파괴되고 다시 생성된다는 것을 말해줍니다. 이 경우, 그 이유는 무엇입니까? 벡터가 너무 커지면 정말 비효율적 인 것처럼 보입니다. 그런 경우가 아니라면 정확히 무엇이 발생합니까?

+4

'용량'과 '예약'을 찾으십시오. –

+0

벡터는 상각 된 일정한 후 삽입 시간을 제공하므로, 큰 사이즈에서는 실제로 비효율적이지 않습니다. 모두에게 괜찮은 것은 아니지만 가장 일반적인 용도로는 좋습니다. – chris

+1

또한 실제로 발생하는 것을 확인하기 위해 Move 컨스트럭터 'MyClass (MyClass &&) noexcept; 및/또는 복사 생성자'MyClass (const MyClass &); '를 사용하여 벡터 요소를 만드는 데 사용됩니다. 그들을 위해 호출 된 기본 생성자가 표시되지 않습니다. 더 큰 값의 경우 루프를 통해 매번 발생하지 않아야하지만 한도가 너무 작아서이를 관찰 할 수 없습니다. – aschepler

답변

0

벡터는 일부 공간을 사전 할당합니다.

예를 들어, 초기 크기는 2 요소 일 수 있습니다. 세 번째를 푸시하면 4 개의 요소가 다시 할당됩니다. 다섯 번째 요소를 푸시하려고하면 8 개의 요소를 다시 할당합니다.

그 이유는 보유하고있는 요소의 수와 용량 (용량 재 할당 전에 몇 개의 요소를 저장할 수 있는지)을 나타내는 .capacity()를 반영한 ​​.size()가있는 이유입니다. .reserve()를 호출하여 해당 용량을 수동으로 처리 할 수 ​​있습니다.

원래 질문에 대답하려면 재 배열을 위해 이전 배열의 모든 요소를 ​​더 큰 것으로 복사해야합니다. 이전 요소를 삭제하고 새로운 요소를 만들어야합니다. 당신이 소멸자 호출하지만 일치하는 생성자 호출을 본 경우 기본 생성자를 사용하지 않기 때문에 , 이것은이지만, 복사 생성자 :

MyClass(const MyClass&) 

이 생성자는 하나의 객체가 매개 변수가 필요하고 구성하는 데 사용 새 객체를 초기화합니다.

덧글에서 언급했듯이 : 재 할당/복사 프로세스는 비용이 많이 드는 것처럼 보일 수 있지만 평균적으로 실제로는 일정한 시간 작업을 구성합니다. 이는 필요한 공간을 필요에 따라 다시 할당하지 않기 때문에 재 할당 및 복사 비용이 상환되고 향후 삽입되기 때문에 발생합니다.