2010-01-27 16 views
51

Czy są jakieś wady przy użyciu make_shared<T>() zamiast używania shared_ptr<T>(new T).Czy są jakieś minusy z używaniem make_shared do tworzenia shared_ptr

Boost documentation stany

Nie zostały powtórzone żądania od użytkowników dla funkcji fabrycznego że tworzy obiekt danego typu i Zwraca shared_ptr do niego. Poza wygody i stylu, taka funkcja jest również bezpieczny wyjątek i znacznie szybciej, ponieważ można go używać pojedynczy alokacji zarówno dla obiektu i jej odpowiednia kontrola bloku, eliminując znaczną część shared_ptr za budowlanego napowietrznych. Eliminuje to jedną z poważnych skarg dotyczących wydajności o wartości shared_ptr.

+6

Można się zastanawiać, jakie są inne poważne skargi dotyczące wydajności dotyczące shared_ptr? –

+0

Bezpieczeństwo wyjątków jest dość mocnym * zasobem * słowa 'std :: make_shared'. Staraj się go używać, gdy tylko jest to możliwe. –

+0

@ViktorSehr Mutex blokuje licznik odwołań, gdy 'shared_ptr' jest kopiowany głównie :) – Drax

Odpowiedz

26

Znam co najmniej dwa.

  • Musisz mieć kontrolę nad przydziałem. Nie jest to naprawdę duży problem, ale niektóre starsze aplikacje lubią zwracać wskazówki, które należy usunąć.
  • Brak niestandardowego deletera. Nie wiem, dlaczego nie jest to obsługiwane, ale tak nie jest. Oznacza to, że twoje współdzielone wskaźniki muszą korzystać z delikatesu waniliowego.

Bardzo słabe punkty. więc staraj się zawsze używać make_shared.

+6

Nie ma niestandardowego deltera, ponieważ tylko 'make_shared' sam wie, jak usunąć obiekt. –

+4

Niestandardowy deleter służy do wykonywania interesujących trików, nie ograniczając się jedynie do usuwania, dlatego deft_code wspomniał o tym. – Catskul

+0

Jeśli możesz dodać niestandardowy deleter, to powinieneś mieć możliwość niestandardowego alokatora; załóżmy, że zbyt skomplikowałoby to interfejs. – ipapadop

37

Oprócz punktów przedstawiony przez @deft_code, jeszcze słabszy:

  • Jeśli używasz weak_ptr s, które żyją po wszystkich shared_ptr s do danego obiektu zmarło, a pamięć tego obiektu będzie żyć w pamięci wraz z blokiem kontrolnym do momentu śmierci ostatniej słabej ścieżki. Innymi słowy, obiekt jest niszczony, ale nie jest anulowany, dopóki nie zostanie zniszczony ostatni.
+1

Jest tak również w przypadku, gdy nie używasz 'make_shared'. Jedyna różnica polega na tym, że blok sterujący będzie w osobno przydzielonej bryle pamięci. –

+13

@Mike: na pewno nie - normalnie, jeśli nie ma wspólnych obiektów do obiektu, tylko weak_ptrs, obiekt jest natychmiast usuwany. Nie wiem od ręki, czy blok kontrolny pozostaje, wezmę na to twoje słowo. Przy make_shared, blok kontrolny i obiekt kojarzą się z pojedynczą alokacją, więc jeśli pamięć dla jednego z nich pozostanie, to oba robią (chociaż zgaduję, że obiekt jest niszczony, tylko pamięć nie została uwolniona?). –

+3

Er, tak. Przepraszam. Musiałem mieć swój drugi mózg, kiedy to napisałem. –

14

Z http://www.codesynthesis.com/~boris/blog/2010/05/24/smart-pointers-in-boost-tr1-cxx-x0/

Inną wadą make_shared() realizacji jest zwiększenie wielkości kodu wynikowego. Ze względu na sposób implementacji tej optymalizacji zostanie utworzona dodatkowa tabela wirtualna oraz zestaw funkcji wirtualnych dla każdego typu obiektu, którego używasz przy użyciu make_shared().

+0

Czy oczekuje się, że będzie się on nadal pojawiał w miarę postępu kompilacji? – Catskul

7

z make wspólne nie można określić jak przydział i dealokacji posiadanego obiektu zostanie wykonana.

Gdy jest to wskazane, należy std::allocate_shared<T> zamiast:

std::vector<std::shared_ptr<std::string>> avec; 
std::allocator<std::string> aAllocator; 
avec.push_back(std::allocate_shared<std::string>(aAllocator,"hi there!")); 

uwaga, że ​​wektor nie musi być informowany o podzielnika!

Do tworzenia niestandardowych przydzielania, zajrzyj tutaj https://stackoverflow.com/a/542339/1149664

8

Dodatkowo make_shared nie jest zgodny z wzorem fabrycznych. Wynika to z tego, że wywołanie funkcji make_shared w ramach funkcji fabrycznej wywołuje kod biblioteki, który z kolei wywołuje new, do której nie ma dostępu, , ponieważ nie może wywołać prywatnego konstruktora klasy (klas) (konstruktor (-y) powinien (powinny) być prywatne, jeśli prawidłowo stosujesz wzór fabryczny).

Powiązane problemy