2016-09-23 2 views
3

Was passiert, wenn eine Ausnahme in std::vector<>::emplace_back() ausgelöst wird?Ausnahme in std :: vector <> :: emplace_back() sicher?

Zum Beispiel:

class Foo { 
public: 
    Foo(int bar) { 
    if (bar == 4) throw std::exception("Something went wrong"); 
    } 
} 

und

std::vector<std::unique_ptr<Foo>> foo_list; 
foo_list.emplace_back(new Foo(3)); 
try { 
    foo_list.emplace_back(new Foo(4)); 
} catch (std::exception error) { 
    // How bad is it? 
} 
// Whats inside foo_list now? 

Ich würde der Vektor erwarten, enthält nur das erste Objekt Foo.

Ist das der Fall? Und ist das vom Standard garantiert?

Und auch: Könnte es Speicherlecks geben?

+1

emplace_back wird nicht ausgeführt, wenn die Ausnahme ausgelöst wird ... –

+0

http://en.cppreference.com/w/cpp/container/vector/emplace_back siehe selbst – Hayt

+3

Sie müssen die Funktionsargumente vor dem Aufruf einer Funktion auswerten. Der Konstruktor wirft zuerst. emplace_back wurde nie aufgerufen. –

Antwort

8

Ich würde erwarten, dass der Vektor nur das erste Foo-Objekt enthält.

Ist das der Fall? Und ist das vom Standard garantiert?

Ja. Die obigen Kommentare haben bereits erläutert, dass emplace_back nie aufgerufen wird, weil der Foo-Konstruktor beim Initialisieren der Argumente für die Funktion löst.

Aber ...

Und auch: Könnte es irgendwelche Speicherlecks sein?

Ja, können Sie die anti-Muster verwenden, die ich bei Inserting into a container of smart pointers with emplace_back(new X) beschrieben haben (auch in Overload Journal #134 - August 2016 veröffentlicht).

Das Problem tritt auf, wenn emplace_back den Vektor neu zuordnen muss und das aufgrund fehlender Speicherkapazität fehlschlägt. Der Zeiger, der an die Funktion übergeben wird, geht verloren, und Sie verlieren das Objekt Foo. Dies kann zum ersten Einsetzen passieren (wo der Foo Konstruktor wirft nicht):

foo_list.emplace_back(new Foo(3)); 

Nie emplace_back verwenden rohe Zeiger in einen Behälter mit unique_ptr einzufügen, verwenden Sie stattdessen make_unique:

foo_list.emplace_back(std::make_unique<Foo>(3)); 

Or wenn Sie 11 verwenden, haben C++ dann die unique_ptr konstruieren und einfügen oder einzulagern, dass, kein Rohzeiger:

foo_list.emplace_back(std::unique_ptr<Foo>(new Foo(3))); 

Auf diese Weise gehört das Objekt sofort zu einem unique_ptr, und wenn innerhalb von emplace_back eine Ausnahme auftritt, wird das Objekt korrekt zerstört.

+0

Danke, und schöne Journal übrigens! Ich wusste zum Beispiel auch nichts von std :: tie. Sehr hilfreich :) –

Verwandte Themen