2013-04-03 10 views
12

eine übliche Basis -> Hierarchie abgeleitet, wie:Sollte ich C++ 11 emplace_back mit Zeigern Containern verwenden?

class Fruit { ... }; 
class Pear : Fruit { ... }; 
class Tomato : Fruit { ... }; 

std::vector<Fruit*> m_fruits; 

Hat es Sinn (z: es eine bessere Leistung hat) statt push_back zu verwenden emplace_back?

std::vector::emplace_back(new Pear()); 
std::vector::emplace_back(new Tomato()); 
+2

Sie werden nicht wissen, bis Sie Benchmark/Profil –

+5

es Verwenden 'std :: vector >' um Speicherlecks zu vermeiden, ist die Antwort offensichtlich. – ipc

+0

Ich Leser, der emplace_back baut sich das Objekt, aber im Falle von Zeigern habe ich keine Ahnung, ob Sinn haben. – Zhen

Antwort

9

Pointers skalaren Typen sind und daher wörtliche Typen und so kopieren, verschieben und den Bau emplace (von einem L-Wert oder R-Wert) sind alle gleichwertig und wird in der Regel zu identischem Code (ein Skalar kompilieren Kopieren). push_back ist klarer, dass Sie eine skalare Kopie ausführen, während emplace_back für emplace Konstruktion reserviert sein sollte, die einen Nicht-Kopie- oder Move-Konstruktor aufruft (z. B. einen Converting- oder Multi-Argument-Konstruktor).

Wenn Ihr Vektor std::unique_ptr<Fruit> anstelle von rohen Zeigern enthalten sollte (um Speicherlecks zu vermeiden), dann, weil Sie einen konvertierenden Konstruktor aufrufen, wäre emplace_back korrekter. Wie dem auch noch austreten kann, wenn der Vektor erstreckt ausfällt, so in diesem Fall sollten Sie push_back(make_unique<Pear>()) verwenden usw.

+0

make_unique ist nicht in der standar, und es scheint, dass emplace_back ist das gleiche wie push_back (std :: move (X)) [Ich benutze gcc 4.7] – Zhen

+2

@Zhen: Es mag so aussehen, aber es ist nicht. 'emplace_back (new T())' kann * leak *, während 'push_back (make_unique ())' nicht kann. Und ja, 'make_unique' fehlt in der Übersicht, Sie können Implementierungen im Internet finden. – GManNickG

+1

'std :: make_unique()' wurde in C++ 14 hinzugefügt. –

13

nicht roh Zeiger Verwenden Sie dieses std::unique_ptr wie verwenden:

std::vector<std::unique_ptr<Fruit>> m_fruits; 

Und wie Sie kein std::unique_ptr konstruieren kopieren können Sie verwenden, muss emplace_back (obwohl Sie push_back mit std::move verwenden können).

 
m_fruits.emplace_back(new Pear()); 
m_fruits.emplace_back(new Tomato()); 

Edit:

Wie es scheint, dass std::vector<std::unique_ptr<T>>::emplace_back und new zu verwenden, wenn der std::vector Bedarf austreten kann und versagt Speicher neu zuzuordnen, mein empfohlene Ansatz (bis C++ 14 führt std::make_unique) ist zu verwenden push_back wie folgt:

m_fruits.push_back(std::unique_ptr<Fruit>(new Pear)); 
m_fruits.push_back(std::unique_ptr<Fruit>(new Tomato)); 

Oder mit std::make_unique:

m_fruits.push_back(std::make_unique<Pear>()); 
m_fruits.push_back(std::make_unique<Tomato>());