2012-04-25 7 views
7

Testowałem następujący kod:W jakich przypadkach jest konstruktor kopiujący nazwie, jeśli pojemnik jest kopiowany

#include <iostream> 
#include <vector> 

class foo { 
public: 
    int m_data; 
    foo(int data) : m_data(data) { 
     std::cout << "parameterised constructor" << std::endl; 
    } 
    foo(const foo &other) : m_data(other.m_data) { 
     std::cout << "copy constructor" << std::endl; 
    } 
}; 

main (int argc, char *argv[]) { 
    std::vector<foo> a(3, foo(3)); 
    std::vector<foo> b(4, foo(4)); 
    //std::vector<foo> b(3, foo(4)); 
    std::cout << "a = b" << std::endl; 
    a = b; 
    return 0; 
} 

uzyskać

parameterised constructor 
    copy constructor 
    copy constructor 
    copy constructor 
    parameterised constructor 
    copy constructor 
    copy constructor 
    copy constructor 
    copy constructor 
    a = b 
    copy constructor 
    copy constructor 
    copy constructor 
    copy constructor 

Jednakże, jeśli mogę wymienić std::vector<foo> b(4, foo(4)); przez std::vector<foo> b(3, foo(4)); konstruktora kopia nie jest wywoływane przez a = b, a wyjście to

parameterised constructor 
copy constructor 
copy constructor 
copy constructor 
parameterised constructor 
copy constructor 
copy constructor 
copy constructor 
a = b 

Dlaczego w takim przypadku konstruktor kopiowania nie jest wywoływany?

używam g ++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1

+0

To jest naprawdę dziwne ... Jest nawet powtarzalne w idealnym ... – RedX

+0

Sooo cool. :) Ja też to powtórzyłem, choć w to nie wierzyłem. –

+0

może kompilator po prostu przenosi b do a, ponieważ b nie jest używane po przypisaniu? Czy próbowałeś zrobić coś za pomocą b po a = b (drukowanie, itp.)? – user396672

Odpowiedz

12

W pierwszym przypadku, a potrzeby rosną po przypisaniu do niego, co oznacza, że ​​wszystkie jego elementy muszą być przesunięte (i dlatego zniszczony i skonstruowany).

W drugim przypadku a nie musi rosnąć, dlatego używany jest operator przypisania.

Zobacz http://ideone.com/atPt9; dodając przeciążonego operatora przypisania kopiowania, który drukuje komunikat, otrzymujemy następujące dane dla drugiego przykładu:

parameterised constructor 
copy constructor 
copy constructor 
copy constructor 
parameterised constructor 
copy constructor 
copy constructor 
copy constructor 
a = b 
copy assignment 
copy assignment 
copy assignment 
+0

Jednakże, jak wiemy, struktura "wektorowa" zastrzega pewne elementy zapasowe, w celu zapewnienia amortyzacji stałych prędkości swoich operacji. Dlaczego więc konstruktor kopiowania jest używany za każdym razem, nie pomijając początkowych rozmiarów a i b? –

+0

@Boris: nie jest używane nigdy nie ignoruj ​​początkowych rozmiarów. Cała kwestia polega na tym, że z jedną parą początkowych rozmiarów jest używana, a z drugą nie. Wypróbuj 'std :: vector a (3, foo (3)); std :: vector b (4, foo (4)); a.rezerwacja (4); a = b; '. Zakładając, że wyjaśnienie Oli jest poprawne, myślę, że powinno się skopiować trzykrotnie podczas rezerwy, a następnie skopiować - skonstruować raz podczas przypisania (i skopiować - przypisać trzy razy). Jeśli korzystasz z C++ 11, zwykle "rezerwa" może się przenieść zamiast kopiować, ale IIRC konstruktor zdefiniowany przez użytkownika pomija domyślny konstruktor ruchu. –

+0

@BorisStrandjev: Używając konstruktora 'vector (count, T) ', pojemność jest ustawiana na' count' (nie jest pewna, czy jest to standardowa autoryzacja, czy specyficzna dla implementacji). Zobacz np. http://ideone.com/jngf9. –

3

Korzysta z operatora przypisania.

#include <iostream> 
#include <vector> 

class foo { 
public: 
    int m_data; 
    foo(int data) : m_data(data) { 
     std::cout << "parameterised constructor " << m_data << std::endl; 
    } 
    foo(const foo &other) : m_data(other.m_data) { 
     std::cout << "copy constructor " << m_data << " " << other.m_data << std::endl; 
    } 

    foo& operator= (const foo& other){ 
     std::cout << "assignment operator " << m_data << " " << other.m_data << std::endl; 
    } 
}; 

main (int argc, char *argv[]) { 
    std::vector<foo> a(3, foo(3)); 
    //std::vector<foo> b(4, foo(4)); 
    std::vector<foo> b(3, foo(4)); 
    std::cout << "a = b" << std::endl; 
    a = b; 

    for(std::vector<foo>::const_iterator it = a.begin(); it != a.end(); ++it){ 
     std::cout << "a " << it->m_data << std::endl; 
    } 
    for(std::vector<foo>::const_iterator it = b.begin(); it != b.end(); ++it){ 
     std::cout << "b " << it->m_data << std::endl; 
    } 
    return 0; 
} 
parameterised constructor 3 
copy constructor 3 3 
copy constructor 3 3 
copy constructor 3 3 
parameterised constructor 4 
copy constructor 4 4 
copy constructor 4 4 
copy constructor 4 4 
a = b 
assignment operator 3 4 
assignment operator 3 4 
assignment operator 3 4 
a 3 
a 3 
a 3 
b 4 
b 4 
b 4 

See Olis odpowiedź dlaczego.

+0

@SteveJessop masz rację, poprawiłem go. – RedX

Powiązane problemy