Howard już dobrze odpowiedział na to pytanie, a Nicol przedstawił kilka dobrych uwag na temat korzyści wynikających z posiadania jednego standardowego typu współdzielonego wskaźnika, zamiast wielu niekompatybilnych.
Chociaż całkowicie zgadzam się z decyzją komisji, uważam, że stosowanie w szczególnych przypadkach niezsynchronizowanego shared_ptr
typu podobnego do tego przynosi pewne korzyści , więc zbadałem ten temat kilka razy.
Jeśli nie używam wielu wątków lub jeśli używam wielu wątków, ale nie udostępniam własności wskaźnika między wątkami, atomowy inteligentny wskaźnik jest przesadą.
Z GCC, gdy twój program nie używa wielu wątków shared_ptr nie używa atomic ops do refcount. Odbywa się to poprzez aktualizację liczników odwołań za pomocą funkcji opakowujących, które wykrywają, czy program jest wielowątkowy (w systemie GNU / Linux odbywa się to po prostu przez wykrycie, czy program jest powiązany z libpthread.so
) i odpowiednio wysyłają do operacji atomowych lub nieatomowych.
Wiele lat temu zdałem sobie sprawę, że ponieważ GCC shared_ptr<T>
jest implementowane w postaci __shared_ptr<T, _LockPolicy>
klasy bazowej , możliwe jest użycie klasy bazowej z jednowątkową polityką blokowania nawet w kodzie wielowątkowym, poprzez jawne użycie __shared_ptr<T, __gnu_cxx::_S_single>
. Niestety, ponieważ nie był to zamierzony przypadek użycia, nie działał optymalnie przed GCC 4.9, a niektóre operacje nadal korzystały z funkcji opakowujących i wysyłane do operacji atomowych, mimo że wyraźnie zażądałeś tej _S_single
polityki. Patrz punkt (2) na http://gcc.gnu.org/ml/libstdc++/2007-10/msg00180.htmlaby uzyskać więcej szczegółów i łatkę do GCC, aby umożliwić stosowanie nieatomowej implementacji nawet w aplikacjach wielowątkowych. Siedziałem nad tą poprawką przez lata, ale w końcu zdecydowałem się na to dla GCC 4.9, które pozwala ci użyć szablonu aliasu, takiego jak ten, do zdefiniowania typu współdzielonego wskaźnika, który nie jest bezpieczny dla wątków, ale jest nieco szybszy:
template<typename T>
using shared_ptr_unsynchronized = std::__shared_ptr<T, __gnu_cxx::_S_single>;
Ten typ nie byłby interoperacyjny std::shared_ptr<T>
i byłby bezpieczny w użyciu tylko wtedy, gdy jest zagwarantowane, że shared_ptr_unsynchronized
obiekty nigdy nie będą współużytkowane między wątkami bez dodatkowej synchronizacji dostarczonej przez użytkownika.
Jest to oczywiście całkowicie nieprzenośne, ale czasami jest to w porządku. Z właściwymi hackami preprocesora, twój kod nadal działałby dobrze z innymi implementacjami, gdyby shared_ptr_unsynchronized<T>
był aliasem dla shared_ptr<T>
, byłby trochę szybszy z GCC.
Jeśli używasz GCC w wersji wcześniejszej niż 4.9, możesz to wykorzystać, dodając _Sp_counted_base<_S_single>
jawne specjalizacje do własnego kodu (i upewniając się, że nikt nigdy nie tworzy instancji __shared_ptr<T, _S_single>
bez uwzględnienia specjalizacji, aby uniknąć naruszeń ODR). Dodanie takich specjalizacji std
typów jest technicznie niezdefiniowane, ale byłoby w praktyce, bo w tym przypadku nie ma różnicy między mną dodaniem specjalizacji do GCC, a Tobą dodaniem ich do własnego kodu.