Шаблон класса shared_ptr хранит указатель на динамически выделенный объект, обычно с C++ new-expression. Указанный объект гарантированно удаляется при уничтожении или сбросе последнего shared_ptr, указывающего на него.
Example:
shared_ptr<X> p1( new X );
shared_ptr<void> p2( new int(5) );
shared_ptr удаляет точный указатель, который был пройден во время строительства, в комплекте с его исходным типом, независимо от параметра шаблона. Во втором примере выше, когда p2 разрушается или сбрасывается, он вызовет delete на исходном int*, который был передан конструктору, даже если p2 сам по себе имеет тип shared_ptr и сохраняет указатель типа void*.
Каждый shared_ptr соответствует требованиям стандартной библиотеки C++ CopyConstructible, MoveConstructible, CopyAssignable и MoveAssignable и может использоваться в стандартных библиотечных контейнерах. Операторы сравнения поставляются таким образом, чтобы shared_ptr работал с ассоциативными контейнерами стандартной библиотеки.
Поскольку реализация использует подсчет ссылок, циклы экземпляров shared_ptr не будут восстановлены. Например, если main() удерживает shared_ptr до A, который прямо или косвенно удерживает shared_ptr обратно до A, A будет равняться 2. Уничтожение исходного shared_ptr оставит A болтающимся с количеством использования 1. Используйте weak_ptr для "разрыва циклов"
Шаблон класса параметризуется по T, типу объекта, на который указывается. shared_ptr и большинство его функций-членов не предъявляют никаких требований к T; допускается неполный тип или void. Функции-члены, которые устанавливают дополнительные требования (конструкторы , сброс ), четко документированы ниже.
shared_ptr может быть неявно преобразован в shared_ptr всякий раз, когда T* может быть неявно преобразован в U*. В частности, shared_ptr неявно конвертируется в shared_ptr, в shared_ptr, где U является доступной базой T, и в shared_ptr.
shared_ptr теперь является частью стандарта C++11, как std::shared_ptr.
Начиная с Boost release 1.53, shared_ptr можно использовать для удержания указателя на динамически выделенном массиве. Это достигается с помощью типа массива (T[] или T[N]) в качестве параметра шаблона. Почти нет разницы между использованием массива неразмерного размера T[] и массива размера T[N]; последний просто позволяет оператору выполнить проверку диапазона индекса.
Example:
shared_ptr<double[1024]> p1( new double[1024] );
shared_ptr<double[]> p2( new double[n] );
Best Practices
Простой принцип, который почти исключает возможность утечки памяти: всегда используйте поименованную переменную умного указателя для удержания результата new. Каждое появление ключевого слова new в коде должно иметь форму:
shared_ptr<T> p(new Y);
Конечно, допустимо использовать другой интеллектуальный указатель вместо shared_ptr выше; наличие T и Y одинакового типа или передача аргументов конструктору Y также нормально.
Если вы соблюдаете это руководство, естественно, что у вас не будет явных утверждений delete; try/catch конструкции будут редкими.
Избегайте использования неназванных времен shared_ptr для сохранения типизации; чтобы понять, почему это опасно, рассмотрим этот пример:
void f(shared_ptr<int>, int);
int g();
void ok()
{
shared_ptr<int> p( new int(2) );
f( p, g() );
}
void bad()
{
f( shared_ptr<int>( new int(2) ), g() );
}
Функция ok следует руководству к букве, тогда как bad конструирует временный shared_ptr на месте, допуская возможность утечки памяти. Поскольку аргументы функции оцениваются в неопределенном порядке, возможно, что сначала будет оценена новая int(2), g() вторая, и мы никогда не сможем добраться до shared_ptrконструктора, если g бросит исключение. См. Лечение Херба Саттера (также здесь ) для получения дополнительной информации.
Проблема безопасности исключения, описанная выше, также может быть устранена с помощью функций завода make_shared или allocate_shared, определенных в boost/make_shared.hpp. Эти заводские функции также обеспечивают эффективность за счет консолидации ассигнований.
Synopsis
namespace boost {
class bad_weak_ptr: public std::exception;
template<class T> class weak_ptr;
template<class T> class shared_ptr {
public:
typedef see belowelement_type;
shared_ptr(); // never throws
shared_ptr(std::nullptr_t); // never throws
template<class Y> explicit shared_ptr(Y * p);
template<class Y, class D> shared_ptr(Y * p, D d);
template<class Y, class D, class A> shared_ptr(Y * p, D d, A a);
template<class D> shared_ptr(std::nullptr_t p, D d);
template<class D, class A> shared_ptr(std::nullptr_t p, D d, A a);
~shared_ptr(); // never throws
shared_ptr(shared_ptr const & r); // never throws
template<class Y> shared_ptr(shared_ptr<Y> const & r); // never throws
shared_ptr(shared_ptr && r); // never throws
template<class Y> shared_ptr(shared_ptr<Y> && r); // never throws
template<class Y> shared_ptr(shared_ptr<Y> const & r, element_type * p); // never throws
template<class Y> shared_ptr(shared_ptr<Y> && r, element_type * p); // never throws
template<class Y> explicit shared_ptr(weak_ptr<Y> const & r);
template<class Y> explicit shared_ptr(std::auto_ptr<Y> & r);
template<class Y> shared_ptr(std::auto_ptr<Y> && r);
template<class Y, class D> shared_ptr(std::unique_ptr<Y, D> && r);
shared_ptr & operator=(shared_ptr const & r); // never throws
template<class Y> shared_ptr & operator=(shared_ptr<Y> const & r); // never throws
shared_ptr & operator=(shared_ptr const && r); // never throws
template<class Y> shared_ptr & operator=(shared_ptr<Y> const && r); // never throws
template<class Y> shared_ptr & operator=(std::auto_ptr<Y> & r);
template<class Y> shared_ptr & operator=(std::auto_ptr<Y> && r);
template<class Y, class D> shared_ptr & operator=(std::unique_ptr<Y, D> && r);
shared_ptr & operator=(std::nullptr_t); // never throws
void reset(); // never throws
template<class Y> void reset(Y * p);
template<class Y, class D> void reset(Y * p, D d);
template<class Y, class D, class A> void reset(Y * p, D d, A a);
template<class Y> void reset(shared_ptr<Y> const & r, element_type * p); // never throws
T & operator*() const; // never throws; only valid when T is not an array type
T * operator->() const; // never throws; only valid when T is not an array type
element_type & operator[](std::ptrdiff_t i) const; // never throws; only valid when T is an array type
element_type * get() const; // never throws
bool unique() const; // never throws
long use_count() const; // never throws
explicit operator bool() const; // never throws
void swap(shared_ptr & b); // never throws
template<class Y> bool owner_before(shared_ptr<Y> const & rhs) const; // never throws
template<class Y> bool owner_before(weak_ptr<Y> const & rhs) const; // never throws
};
template<class T, class U>
bool operator==(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws
template<class T, class U>
bool operator!=(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws
template<class T, class U>
bool operator<(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws
template<class T>
bool operator==(shared_ptr<T> const & p, std::nullptr_t); // never throws
template<class T>
bool operator==(std::nullptr_t, shared_ptr<T> const & p); // never throws
template<class T>
bool operator!=(shared_ptr<T> const & p, std::nullptr_t); // never throws
template<class T>
bool operator!=(std::nullptr_t, shared_ptr<T> const & p); // never throws
template<class T> void swap(shared_ptr<T> & a, shared_ptr<T> & b); // never throws
template<class T> typename shared_ptr<T>::element_type * get_pointer(shared_ptr<T> const & p); // never throws
template<class T, class U>
shared_ptr<T> static_pointer_cast(shared_ptr<U> const & r); // never throws
template<class T, class U>
shared_ptr<T> const_pointer_cast(shared_ptr<U> const & r); // never throws
template<class T, class U>
shared_ptr<T> dynamic_pointer_cast(shared_ptr<U> const & r); // never throws
template<class T, class U>
shared_ptr<T> reinterpet_pointer_cast(shared_ptr<U> const & r); // never throws
template<class E, class T, class Y>
std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, shared_ptr<Y> const & p);
template<class D, class T>
D * get_deleter(shared_ptr<T> const & p);
}
Members
element_type
typedef ... element_type;
element_type является T, когда T не является типом массива, и U, когда T является U[1] или U[N].
default constructor
shared_ptr(); // never throws
shared_ptr(std::nullptr_t); // never throws
Эффекты: Построение пустого shared_ptr.
Постусловия: use_count() == 0&& get() == 0.
Броски: ничего.
[Гарантия нотроу важна, так как перезагрузка() указана в терминах конструктора по умолчанию; это означает, что конструктор не должен выделять память]
pointer constructor
template<class Y> explicit shared_ptr(Y * p);
Требования: Y должны быть полного типа. Выражение delete[] p, когда T является типом массива, или delete p, когда T не является типом массива, должно быть хорошо сформировано, не должно вызывать неопределенное поведение и не должно выбрасывать исключения. Когда TU[N], Y (*) [N] должен быть конвертируемым в T*; когда T является U[], Y (*) [] должен быть конвертируемым в T*; в противном случае Y* должен быть конвертируемым в T*.
Эффекты: Когда T не является типом массива, конструирует shared_ptr, который владеет Указатель p. В противном случае конструируется shared_ptr, который владеет p, и удалятель неопределенного типа, который вызывает delete[] p.
Постусловия: use_count() == 1 && get() == p. Если T не является типом массива и p однозначно конвертируется в enable_shared_from_this* для некоторых V, p->shared_from_this() возвращает копию *this.
Броски:std::bad_alloc или исключение, определяемое реализацией, когда ресурс, отличный от памяти, не может быть получен.
Безопасность исключения: Если бросается исключение, конструктор вызывает delete[] p, когда T является типом массива, или delete p, когда T не является типом массива.
Примечания: p должен быть указателем на объект, который был выделен через C++ новое выражение или быть 0. Пост-условие, что использовать граф 1 удерживает, даже если p равно 0; вызов удалить на указателе, который имеет значение 0, безвреден.
[Этот конструктор представляет собой шаблон для запоминания фактического пройденного типа указателя.] Деструктор вызовет delete с тем же указателем, в комплекте с его исходным типом, даже если T не имеет виртуального деструктора, или void.
constructors taking a deleter
template<class Y, class D> shared_ptr(Y * p, D d);
template<class Y, class D, class A> shared_ptr(Y * p, D d, A a);
template<class D> shared_ptr(std::nullptr_t p, D d);
template<class D, class A> shared_ptr(std::nullptr_t p, D d, A a);
Требования: D должны быть CopyConstructible. Конструктор копий и разрушитель D не должны выбрасываться. Выражение d(p) должно быть хорошо сформировано, не должно вызывать неопределенного поведения и не должно бросать исключений. A должен быть Allocator, как описано в разделе 20.1.5 (Allocator requirements) C++ Стандартно. Когда TU[N], Y (*) [N] должен быть конвертируемым в T*; когда T является U[], Y (*) [] должен быть конвертируемым в T*; в противном случае Y* должен быть конвертируемым в T*.
Влияние: Построение shared_ptr, при котором владеет указателем p и удаляющим d. Конструкторы, принимающие распределитель a, выделяют память, используя копию a.
Постусловия: use_count() == 1 && get() == p. Если T не является типом массива и p однозначно конвертируется в enable_shared_from_this* для некоторых V, p->shared_from_this() возвращает копию *this.
Броски:std::bad_alloc или исключение, определяемое реализацией, когда ресурс, отличный от памяти, не может быть получен.
Безопасность исключения: Если забрасывается исключение, называется d(p).
Примечания: Когда приходит время удалить объект, на который указывает p, сохраненная копия d вызывается с сохраненной копией p в качестве аргумента.
[Таможенные распределители позволяют заводской функции возвращать shared_ptr, чтобы изолировать пользователя от его стратегии распределения памяти. Поскольку дилер не является частью типа, изменение стратегии распределения не нарушает исходную или двоичную совместимость и не требует перекомпиляции клиента. Например, блокатор без операции полезен при возврате shared_ptr к статически выделенному объекту, а другие варианты позволяют использовать shared_ptr в качестве обертки для другого умного указателя, облегчая совместимость.
Поддержка пользовательских дилеров не накладывает значительных накладных расходов. Другие функции shared_ptr по-прежнему требуют сохранения оператора связи.
Требование, чтобы конструктор копий D не выбрасывал, исходит из пропуска по значению. Если конструктор копий бросит, указатель просочится.[3]
copy and converting constructors
shared_ptr(shared_ptr const & r); // never throws
template<class Y> shared_ptr(shared_ptr<Y> const & r); // never throws
Требования: Y* следует конвертировать в T*.
Эффекты: Если r пустой, конструирует пустойshared_ptr; в противном случае конструирует shared_ptr, который разделяет право собственности с r.
Эффекты: Построение shared_ptr, как если бы путем хранения копии r.release().
Постусловия: use_count() == 1.
Броски:std::bad_alloc или исключение, определяемое реализацией, когда ресурс, отличный от памяти, не может быть получен.
Безопасность исключения: Если забрасывать исключение, то конструктор не имеет никакого эффекта.
unique_ptr constructor
template<class Y, class D> shared_ptr(std::unique_ptr<Y, D> && r);
Требования: Y* следует конвертировать в T*.
Эффекты: Эквивалент shared_ptr(r.release(), r.get_deleter()), когда D не является эталонным типом. В противном случае, эквивалентно shared_ptr(r.release(), del), где del является удаляющим устройством, которое хранит ссылку rd Возвращается из r.get_deleter() и del(p) вызовов rd(p).
Постусловия: use_count() == 1.
Броски:std::bad_alloc или исключение, определяемое реализацией, когда ресурс, отличный от памяти, не может быть получен.
Безопасность исключения: Если забрасывать исключение, то конструктор не имеет никакого эффекта.
destructor
~shared_ptr(); // never throws
Эффекты:
Если*thisпустойилиакции собственностис другимshared_ptrэкземпляром (use_count() > 1), нет побочных эффектов.
В противном случае, если*thisвладеетуказателемpи удаляющимd,d(p)называется.
В противном случае*thisвладеетуказателемp, иdelete pназывается.
Примечания: Обновления подсчета использования, вызванные временным строительством и разрушением объекта, не считаются наблюдаемыми побочными эффектами, и реализация свободна для удовлетворения эффектов (и подразумеваемых гарантий) различными способами, без создания временного. В частности, в примере:
Требования: T не должны быть типом массива. Сохраненный указатель не должен быть 0.
Возвращает: ссылку на объект, на который указывает сохраненный указатель.
Броски: ничего.
T * operator->() const; // never throws
Требования: T не должны быть типом массива. Сохраненный указатель не должен быть 0.
Возвращает: сохраненный указатель.
Броски: ничего.
element_type & operator[](std::ptrdiff_t i) const; // never throws
Требования: T должны быть типа массива. Сохраненный указатель не должен быть 0. i >= 0. Если TU[N], i .
Возврат: get()[i].
Броски: ничего.
get
element_type * get() const; // never throws
Возвращает: сохраненный указатель.
Броски: ничего.
unique
bool unique() const; // never throws
Возврат: use_count() == 1.
Броски: ничего.
Примечания: уникальный() может быть быстрее, чем use_count(). Если вы используете unique() для реализации копирования при записи, не полагайтесь на конкретное значение, когда сохраненный указатель равен нулю.
use_count
long use_count() const; // never throws
Возврат: количество объектов shared_ptr, *это включено, что share ownership с это , или 0, когда *этопустое.
Броски: ничего.
Примечания: use_count() необязательно эффективен. Используйте только для отладки и тестирования, а не для производственного кода.
conversions
explicit operator bool() const; // never throws
Возврат: get()!= 0.
Броски: ничего.
Примечания: Этот оператор преобразования позволяет использовать объекты shared_ptr в булевых контекстах, таких как if(p && p->valid()) {}.
[Переход в бул — это не просто синтаксический сахар.] Он позволяет декларировать shared_ptr в условиях использования dynamic_pointer_cast или weak_ptr::lock.
swap
void swap(shared_ptr & b); // never throws
Эффекты: Обмен содержимого двух интеллектуальных указателей.
template<class T, class U>
bool operator<(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws
Возврат: неопределенное значение, такое, что
operator<— строгая слабая упорядоченность, описанная в разделе 25.3[lib.alg.sorting]стандарта C++;
В соответствии с отношением эквивалентности, определеннымoperator<,!(a
< b) && !(b < a), дваshared_ptrэкземпляра эквивалентны, если и только если онидолевого владенияили обапусты.
Броски: ничего.
Примечания: Позволяет использовать объекты shared_ptr в качестве ключей в ассоциативных контейнерах.
[Operator< предпочтительнее специализации std::less по соображениям согласованности и законности, поскольку std::less требуется для возврата результатов operator<, а многие стандартные алгоритмы используют operator< вместо std::less для сравнений, когда предикат не поставляется. Композитные объекты, такие как std::pair, также реализуют своего оператора< с точки зрения содержащихся в них подобъектов. оператор<.<19
Остальные операторы сравнения опущены по дизайну.
swap
template<class T>
void swap(shared_ptr<T> & a, shared_ptr<T> & b); // never throws
Эффекты: Эквивалент a.swap(b).
Броски: ничего.
Примечания: Соответствует интерфейсу std::swap. Предоставляется в качестве помощи для общего программирования.
[swap определяется в том же пространстве имен, что и shared_ptr, поскольку в настоящее время это единственный законный способ предоставления функции swap, которая имеет возможность использоваться стандартной библиотекой.]
Примечания: кажущееся эквивалентным выражение shared_ptr(static_cast(r.get())) в конечном итоге приведет к неопределенному поведению, пытаясь дважды удалить один и тот же объект.
const_pointer_cast
template<class T, class U>
shared_ptr<T> const_pointer_cast(shared_ptr<U> const & r); // never throws
Требуется: Выражение const_cast((U*)0) должно быть хорошо сформировано.
template<class E, class T, class Y>
std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, shared_ptr<Y> const & p);
Последствия:os << p.get();.
Возврат: os.
get_deleter
template<class D, class T>
D * get_deleter(shared_ptr<T> const & p);
Возврат: Если *это владеет удалителем d типа (cv-неквалифицированный) D, возврат &d; в противном случае возвращается 0.
Броски: ничего.
Example
См. shared_ptr_example.cpp для полной примерной программы. Программа строит std::vector и std::set объектов shared_ptr.
Обратите внимание, что после заполнения контейнеров некоторые из shared_ptr Объекты будут иметь число использования 1 вместо числа использования 2, так как набор является std::set, а не std::multiset, и, таким образом, не содержит дублирующих записей. Кроме того, количество использования может быть еще выше в разное время, когда выполняются операции с контейнерами push_back и insert. Более сложные, однако, контейнерные операции могут привести к исключениям при различных обстоятельствах. Получение управления памятью и обработки исключений в этом примере без умного указателя было бы кошмаром.
Handle/Body Idiom
Одним из распространенных способов использования shared_ptr является реализация идиомы «ручка/тело» (также называемой pimpl), которая позволяет избежать раскрытия тела (реализации) в файле заголовка.
Программа выборки shared_ptr_example2_test.cpp содержит файл заголовка, shared_ptr_example2.hpp, который использует shared_ptr для сокрытия реализации. Инстантификация функций-членов, требующих полного типа, происходит в файле реализации shared_ptr_example2.cpp. Обратите внимание, что нет необходимости в явном деструкторе. В отличие от ~scoped_ptr, ~shared_ptr не требует, чтобы T был полным типом.
Thread Safety
Объекты shared_ptr обеспечивают тот же уровень безопасности потока, что и встроенные типы. Экземпляр shared_ptr может быть «прочитан» (доступен только с использованием операций const) одновременно несколькими потоками. Различные экземпляры shared_ptr могут быть «записаны» (получены с использованием изменяемых операций, таких как operator= или reset) одновременно несколькими потоками (даже когда эти экземпляры являются копиями, и имеют одинаковое количество ссылок внизу)
Любой другой одновременный доступ приводит к неопределенному поведению.
Примеры:
shared_ptr<int> p(new int(42));
//--- Example 1 ---
// thread A
shared_ptr<int> p2(p); // reads p
// thread B
shared_ptr<int> p3(p); // OK, multiple reads are safe
//--- Example 2 ---
// thread A
p.reset(new int(1912)); // writes p
// thread B
p2.reset(); // OK, writes p2
//--- Example 3 ---
// thread A
p = p3; // reads p3, writes p
// thread B
p3.reset(); // writes p3; undefined, simultaneous read/write
//--- Example 4 ---
// thread A
p3 = p2; // reads p2, writes p3
// thread B
// p2 goes out of scope: undefined, the destructor is considered a "write access"
//--- Example 5 ---
// thread A
p3.reset(new int(1));
// thread B
p3.reset(new int(2)); // undefined, multiple writes
Начиная с версии 1.33.0 Boost, shared_ptr использует реализацию без блокировки на большинстве распространенных платформ.
Если ваша программа однопоточная и не ссылается на какие-либо библиотеки, которые могли бы использовать shared_ptr в своей конфигурации по умолчанию, вы можете #define макро BOOST_SP_DISABLE_THREADS на проектной основе для перехода на обычные неатомные обновления.
(Определение BOOST_SP_DISABLE_THREADS в некоторых, но не во всех, единицах перевода технически является нарушением Правила Одного Определения и неопределенного поведения.) Тем не менее, реализация пытается сделать все возможное, чтобы удовлетворить просьбу об использовании неатомных обновлений в этих единицах перевода. Но никаких гарантий
Вы можете определить макрос BOOST_SP_USE_PTHREADS, чтобы отключить реализацию платформы без блокировки и вернуться к общему коду на основе pthread_mutex_t.
Frequently Asked Questions
Q. Существует несколько вариантов общих указателей с различными компромиссами; почему библиотека интеллектуальных указателей предлагает только одну реализацию? Было бы полезно иметь возможность экспериментировать с каждым типом, чтобы найти наиболее подходящий для работы под рукой?
А. Важной целью shared_ptr является предоставление стандартного указателя совместного владения. Наличие одного типа указателя важно для стабильных библиотечных интерфейсов, поскольку различные общие указатели обычно не могут взаимодействовать, то есть указатель с подсчетом ссылок (используемый библиотекой A) не может совместно использовать связанный указатель (используемый библиотекой B)
Q. Почему shared_ptr не имеет параметров шаблона, обеспечивающих характеристики или политики, позволяющие обширную настройку пользователя?
А. Параметризация отпугивает пользователей. Шаблон shared_ptr тщательно разработан для удовлетворения общих потребностей без обширной параметризации. Однажды может быть изобретен очень настраиваемый интеллектуальный указатель, который также очень прост в использовании и очень трудно использовать неправильно. До тех пор shared_ptr является интеллектуальным указателем выбора для широкого спектра приложений. (Те, кто интересуется умными указателями на основе политики, должны прочитать: Современный дизайн C++ Андрея Александреску
Q. Я не убежден. Параметры по умолчанию могут использоваться там, где это необходимо, чтобы скрыть сложность. Опять же, почему не политика?
А. Параметры шаблонов влияют на тип. Смотрите ответ на первый вопрос выше.
Q. Почему не shared_ptr Используйте реализацию связанного списка?
А. Реализация связанного списка не предлагает достаточно преимуществ, чтобы компенсировать дополнительную стоимость дополнительного указателя. См. страницу timings. Кроме того, дорого сделать нить реализации связанного списка безопасной.
Q. Почему shared_ptr (или любой другой интеллектуальный указатель Boost) не обеспечивает автоматическое преобразование в T*?
А. Считается, что автоматическое преобразование слишком подвержено ошибкам.
Q. Почему shared_ptr предоставляет use_count()?
А. В качестве помощи при написании тестовых случаев и отладки дисплеев. У одного из прародителей был use_count(), и он был полезен для отслеживания ошибок в сложном проекте, который оказался циклическим.
Q. Почему shared_ptr не определяет требования к сложности?
А. Поскольку требования к сложности ограничивают реализаторы и усложняют спецификацию без очевидной выгоды для пользователей shared_ptr. Например, реализации проверки ошибок могут стать несоответствующими, если они должны соответствовать строгим требованиям сложности.
Q. Почему shared_ptr не обеспечивает функцию release()?
A.shared_ptr не может отказаться от права собственности, если это не unique(), потому что другая копия все равно уничтожит объект.
Подумайте:
shared_ptr<int> a(new int);
shared_ptr<int> b(a); // a.use_count() == b.use_count() == 2
int * p = a.release();
// Who owns p now? b will still call delete on it in its destructor.
Кроме того, указатель, возвращенный release(), будет трудно надежно распределить, поскольку источник shared_ptr Он мог быть создан с помощью специального устройства.
Q. Почему оператор->() const, но его возвращаемое значение является указателем неconst на тип элемента?
А. Неглубокие указатели копирования, включая сырые указатели, обычно не распространяют константу. Для них это не имеет смысла, так как вы всегда можете получить указатель не-конста от первого, а затем перейти к изменению объекта через него. shared_ptr означает «как можно ближе к исходным указателям, но не ближе».
$Date$
Авторское право 1999 Грег Колвин и Беман Доуз. Авторское право 2002 Дарин Адлер. Авторское право 2002-2005, 2012, 2013 Питер Димов. Распространяется под лицензией Boost Software License, версия 1.0. См. сопроводительный файл LICENSE_1_0.txt или копию по адресу http://www.boost.org/LICENSE_1_0.txt
Статья shared_ptr раздела может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.