2015-08-30 6 views
7

Dieser Code wird explodieren, oder? Sobald die Schleife beendet wird, werden die ursprünglichen Instanzen mit allen ihren inneren Elementen abstürzen, wenn sie also keine PODs sind, wird jede Methode wie do_stuff, die Zugriff auf Mitglieder von B erfordert, einen Segmentierungsfehler auslösen, richtig?Ist es nicht möglich, Instanzen in einer Schleife ohne Zeiger zu konstruieren?

void foo() { 
    std::vector<B> bar; 
    for (int i = 0; i < 7; i++) 
    bar.push_back(B(i, i, i)); 
    bar[3].do_stuff(); 
} 

Also, gibt es eine Möglichkeit, dies zu tun, ohne einen Zeiger zu verwenden? Oder haben Sie, dies zu tun haben:

void foo() { 
    std::vector<B*> bar; 
    for (int i = 0; i < 7; i++) 
    bar.push_back(new B(i, i, i)); 
    bar[3]->do_stuff(); 
    for (int i = 0; i < 7; i++) 
    delete bar[i]; 
} 
+1

Der erste Weg ist in Ordnung. Wenn Sie Java verwenden möchten, verwenden Sie 'std :: reference_wrapper'. – chris

+0

auch fwiw Ich glaube nicht, "POD" hat etwas damit zu tun, es ist nur um die Lebensdauer der Objekte. Es ist nicht legal, Methoden für ein Objekt aufzurufen, dessen Lebensdauer abgelaufen ist, POD oder nicht –

+0

So komisch .. Ich hatte die erste Version, bekam immer seg fault => mit Valgrind überprüft, es hieß B :: do_stuff() => in die zweite Version geändert und jetzt funktioniert es gut. Dachte auch, die erste Version sollte funktionieren. So stabil. – zehelvion

Antwort

7

Der erste Code ist besser als der zweite.

Die B Instanzen movedsince C++11/Pre-C++ 11 in den Vektor kopiert werden, damit sie nicht nach der Schleife außerhalb des Bereichs fallen - erst nach dem Vektor aus Anwendungsbereich fällt.


Wenn Sie die absolut optimale Leistung erhalten möchten, dann tun Sie dies:

void foo() { 
    std::vector<B> bar; 
    bar.reserve(7); 
    for (int i = 0; i < 7; i++) 
    bar.emplace_back(i, i, i); 
    bar[3].do_stuff(); 
} 

Dies garantiert nur eine Umverteilung, und die Elemente werden direkt in den Vektor konstruiert (statt verschieben oder kopieren sie dort) laut Marc Glisses Kommentare.

+3

Wenn es C++ 11 war, sollte es emplace_back verwenden und überhaupt nicht bewegen. –

+1

@MarcGlisse Bewegt sich schlecht/gefährlich? – zehelvion

+0

@zehelvion Nein, es ist in diesem Fall nur unnötig. –

12

Das erste Codebeispiel gilt.

std::vector wird eine Kopie der Objekte übergeben Sie sie mit push_back (oder werden bewegen sie an Ort und Stelle mit C 11 ++, wenn Sie eine temporäre sind drängen), und es wird lebendig alle Instanzen halten solange der Vektor selbst lebt.

Die Zerstörung tritt auf, wenn Sie die Funktion beenden, nicht wenn Sie die Schleife verlassen.

+2

"wird eine Kopie erstellen" oder ein __move__. (In diesem Fall wäre es ein Zug, vorausgesetzt, es ist als> = C++ 11 kompiliert.) – emlai

4

Nein, std::vector übernimmt die Eigentümerschaft seiner Mitglieder, so dass der ursprüngliche Code funktioniert.

3

std::vector kopiert die ihm zur Verfügung gestellten Objekte (zB durch push_back()) und behält sie bei, bis der Vektor selbst zerstört wird.

Also der erste Code ist völlig in Ordnung, solange der Kopierkonstruktor von B (B(const B&)) richtig implementiert ist.

Verwandte Themen