2013-04-10 20 views
5

Uczę się C++ i szukałem kontenerów STL. Mam wiele pytań, ale myślę, że to może być pierwsze. Rozważ tę klasę i wektor tego.Dlaczego inicjalizacja wektorowa tworzy i kopiuje?

class A { 
    int i; 
    // A(const A&); 
public: 

    A(int i) : i(i) {cout << "consting " << i << endl;} 
    A(const A& ot) : i(ot.i) {cout << "copying " << i << endl;} 

}; 

int main() { 
    vector<A> v1 = {A(1),A(2),A(3),A(4)}; 
    vector<A> v2(1,A(5)); 
    vector<A> v3; 
    v3.push_back(A(6)); 
} 

daje mi wyjście

consting 1 
consting 2 
consting 3 
consting 4 
copying 1 
copying 2 
copying 3 
copying 4 
consting 5 
copying 5 
consting 6 
copying 6 

Oczywiste jest konstruowanie i kopiując każdy A.

Czy istnieje sposób, aby temu zapobiec. Mam na myśli to, jak mogę uniknąć dodatkowej kopii i po prostu skonstruować A w wektorze. Czy to możliwe. Jeśli nie, ktoś może wyjaśnić, dlaczego? Dziękuję Ci.

EDIT: Wystarczy do realizacji w sake push_back robi to samo

+3

Problemem jest to, że 'std :: initializer_list'„posiada”to zawartość więc każdy konstruktor użyciem musi skopiować elementy . To nie ma sensu, ale tak działa 'std :: initializer_list'. Pech. – ipc

+0

@ipc A co z pozostałymi skrzyniami konstrukcyjnymi? czy to możliwe dla innych? –

+0

@Aurora: W rzeczywistości jest to znacznie łatwiejsze niż myślisz. Zamiast dodawać 'A (6)', po prostu dodaj '6'. –

Odpowiedz

3

nie można uniknąć konieczności kopię przy użyciu konstruktora listy inicjator takiego. Alternatywą jest zarezerwować odpowiednią pojemność na początku, a następnie emplace_back każdego z obiektów:

vector<A> v1; 
v1.reserve(4); 
v1.emplace_back(1); 
v1.emplace_back(2); 
v1.emplace_back(3); 
v1.emplace_back(4); 

As you can see powoduje to tylko następujący wynik:

consting 1 
consting 2 
consting 3 
consting 4 
+0

'emplace_back' jest dostępne tylko w C++ 11, prawda? –

+3

Prawa @Aurora, ale także konstruktor listy inicjalizacyjnej, którego używasz. –

+0

@ Aurora: Prawidłowo. To samo dotyczy inicjowania list, które wydają się być używane w kodzie. –

4

Niestety lista inicjalizacji wymaga kopii z std::vector . Jeśli wiesz, że pojemnik jest stałym rozmiarze, jedna alternatywa jest do korzystania z std::array zamiast:

std::array<A, 4> a1 = {{A(1),A(2),A(3),A(4)}}; 

stdout: 
consting 1 
consting 2 
consting 3 
consting 4 
+0

+1 Dobra sugestia. –

Powiązane problemy