2013-04-03 13 views
12

Posiadanie zwykły Base -> Pochodzące hierarchię, jak:Czy powinienem używać C++ 11 emplace_back z wskaźnikami containters?

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

std::vector<Fruit*> m_fruits; 

ma to sens (np: ma lepszą wydajność) do korzystania emplace_back zamiast push_back?

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

nie będziesz wiedzieć, dopóki nie przetestujesz/profilujesz go –

+5

Użyj 'std :: vector > aby uniknąć wycieków pamięci, odpowiedź jest oczywista. – ipc

+0

Czytam, że emplace_back konstruuje sam obiekt, ale w przypadku wskaźników, nie mam pojęcia, czy ma to sens. – Zhen

Odpowiedz

9

wskaźniki są skalarne i dlatego dosłownych typów, więc kopiowania, przenoszenia i emplace konstrukcja (z lwartości lub rvalue) są równoważne i zazwyczaj kompilacji identycznym kodem (skalarne Kopiuj). push_back jest bardziej przejrzysty, gdy wykonujesz kopię skalarną, natomiast emplace_back powinno być zarezerwowane dla konstrukcji emplace wywołującej konstruktor inny niż copy lub move (na przykład konwerter lub konstruktor wieloargumentowy).

Jeśli Twój wektor powinien zawierać std::unique_ptr<Fruit> zamiast surowych wskaźników (aby zapobiec wyciekom pamięci), to dlatego, że wywołujesz konwertujący konstruktor emplace_back będzie bardziej poprawny. Jednak to może nadal przeciekać, jeśli przedłużenie wektora się nie powiedzie, więc w takim przypadku powinieneś użyć push_back(make_unique<Pear>()) itd.

+0

make_unique nie jest w standardzie i wygląda na to, że emplace_back jest takie samo, że push_back (std :: move (X)) [używam gcc 4.7] – Zhen

+2

@Zhen: Może się tak wydawać, ale tak nie jest. 'emplace_back (new T())' can * leak *, natomiast 'push_back (make_unique ())' nie może. I tak, przez niedopatrzenie brakuje 'make_unique', możesz znaleźć implementacje w Internecie. – GManNickG

+1

'std :: make_unique()' został dodany w C++ 14. –

13

nie wolno używać surowych wskaźników, należy std::unique_ptr tak:

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

A jak nie można skopiować skonstruować std::unique_ptr należy użyć emplace_back (choć można użyć push_back z std::move).

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

Edit: Jak wynika

że używanie std::vector<std::unique_ptr<T>>::emplace_back i new może wyciekać jeżeli std::vector potrzeb i nie trafia do realokacji pamięci, moje Zalecane podejście (do C++ 14 wprowadza std::make_unique) jest użycie push_back w ten sposób:

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

lub za pomocą std::make_unique:

m_fruits.push_back(std::make_unique<Pear>()); 
m_fruits.push_back(std::make_unique<Tomato>()); 
Powiązane problemy