Говард вже добре відповів на питання, і Ніколь зробив кілька хороших зауважень щодо переваг наявності єдиного стандартного спільного типу покажчика, а не безлічі несумісних.
Хоча я повністю погоджуюся з рішенням комітету, я думаю, що є певна користь від використання несинхронізованого shared_ptr
типу в особливих випадках , тому я досліджував тему кілька разів.
Якщо я не використовую кілька потоків, або якщо я використовую декілька потоків, але не розподіляю право власності на вказівник між потоками, атомний розумний вказівник є надмірним.
З GCC, коли ваша програма не використовує кілька потоків, shared_ptr не використовує атомарні операційні системи для перерахунку. Це робиться шляхом оновлення лічильників посилань за допомогою функцій обгортки, які визначають, чи є програма багатопотоковою (на GNU / Linux це робиться просто виявляючи, чи програма посилається на libpthread.so
), і направляючи відповідно до атомних або неатомних операцій.
Багато років тому я зрозумів, що оскільки GCC shared_ptr<T>
реалізовано з точки зору __shared_ptr<T, _LockPolicy>
базового класу , можна використовувати базовий клас з однопотоковою політикою блокування навіть у багатопотоковому коді, явно використовуючи __shared_ptr<T, __gnu_cxx::_S_single>
. На жаль, оскільки це не було передбачуваним випадком використання, він не працював оптимально до GCC 4.9, а деякі операції все ще використовували функції обгортки і тому надсилалися до атомних операцій, навіть якщо ви явно запитували _S_single
політику. Див. Пункт (2) на http://gcc.gnu.org/ml/libstdc++/2007-10/msg00180.htmlдля отримання детальнішої інформації та виправлення для GCC, щоб дозволити неатомну реалізацію використовувати навіть у багатопотокових програмах. Я сидів на цьому патчі роками, але нарешті завершив його для GCC 4.9, що дозволяє використовувати шаблон псевдоніма, як цей, для визначення спільного типу вказівника, який не є безпечним для потоку, але трохи швидший:
template<typename T>
using shared_ptr_unsynchronized = std::__shared_ptr<T, __gnu_cxx::_S_single>;
Цей тип не буде взаємодіяти з ним std::shared_ptr<T>
і буде безпечним у використанні лише тоді, коли гарантується, що shared_ptr_unsynchronized
об’єкти ніколи не будуть спільно використовуватися між потоками без додаткової синхронізації, яку надає користувач.
Це, звичайно, абсолютно не портативно, але іноді це нормально. За умови правильного злому препроцесора ваш код все одно буде добре працювати з іншими реалізаціями, якщо shared_ptr_unsynchronized<T>
це псевдонім, для shared_ptr<T>
GCC це буде просто трохи швидше.
Якщо ви використовуєте GCC до версії 4.9, ви можете скористатися цим, додавши _Sp_counted_base<_S_single>
явні спеціалізації до власного коду (і забезпечивши, щоб ніхто ніколи __shared_ptr<T, _S_single>
не створював екземпляри, не включаючи спеціалізації, щоб уникнути порушень ОДР.) Додавання таких спеціалізацій std
типів технічно не визначено, але працювати на практиці, тому що в цьому випадку немає ніякої різниці між тим, як я додаю спеціалізації до GCC, або тим, що додаю їх до свого коду.