Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

shared_ptr

Boost , ,

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

shared_ptr class template

Введение
Лучшие практики
Синопсис

Бесплатные функции
Пример
Рука/Идиома тела

Безопасность ниток


Умные указательные сроки
Техника программирования

Introduction

Шаблон класса 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 below element_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 не является типом массива, должно быть хорошо сформировано, не должно вызывать неопределенное поведение и не должно выбрасывать исключения. Когда T U[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++ Стандартно. Когда T U[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.

Постусловия: get() == r.get() && use_count() == r.use_count().

Броски: ничего.

move constructors

shared_ptr(shared_ptr && r); // never throws
template<class Y> shared_ptr(shared_ptr<Y> && r); // never throws

Требования: Y* следует конвертировать в T*.

Последствия: Построение shared_ptr из r.

Постусловия: *это содержит старое значение r. r empty и r.get() == 0.

Броски: ничего.

aliasing constructor

template<class Y> shared_ptr(shared_ptr<Y> const & r, element_type * p); // never throws

Эффекты: создает shared_ptr, который разделяет собственность с r и хранит p.

Постусловия: get() == p&& use_count() == r.use_count().

Броски: ничего.

aliasing move constructor

template<class Y> shared_ptr(shared_ptr<Y> && r, element_type * p); // never throws

Влияние: Переместить конструкцию shared_ptr из r, сохраняя вместо этого p.

Постусловия: get() == p и use_count() равно старому счету r. r empty и r.get() == 0.

Броски: ничего.

weak_ptr constructor

template<class Y> explicit shared_ptr(weak_ptr<Y> const & r);

Требования: Y* следует конвертировать в T*.

Эффекты: Построение shared_ptr, который разделяет право собственности с r и сохраняет копию указателя, хранящегося в r.

Постусловия: use_count() == r.use_count().

Броски: bad_weak_ptr, когда r.use_count() == 0.

Безопасность исключения: Если забрасывать исключение, то конструктор не имеет никакого эффекта.

auto_ptr constructors

template<class Y> shared_ptr(std::auto_ptr<Y> & r);
template<class Y> shared_ptr(std::auto_ptr<Y> && r);

Требования: Y* следует конвертировать в T*.

Эффекты: Построение 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называется.

Броски: ничего.

assignment

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);

Эффекты: Эквивалент shared_ptr(r.swap(*this).

Возврат: *это.

Примечания: Обновления подсчета использования, вызванные временным строительством и разрушением объекта, не считаются наблюдаемыми побочными эффектами, и реализация свободна для удовлетворения эффектов (и подразумеваемых гарантий) различными способами, без создания временного. В частности, в примере:

shared_ptr<int> p(new int);
shared_ptr<void> q(p);
p = p;
q = p;

оба задания могут быть безоперационными.

shared_ptr & operator=(shared_ptr && r); // never throws
template<class Y> shared_ptr & operator=(shared_ptr<Y> && r); // never throws
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(std::move(r))swap(*this).

Возврат: *это.

shared_ptr & operator=(std::nullptr_t); // never throws

Эффекты: Эквивалент shared_ptr(.swap(*this).

Возврат: *это.

reset

void reset(); // never throws

Эффекты: Эквивалент shared_ptr(.swap(*this).

template<class Y> void reset(Y * p);

Эффекты: Эквивалент shared_ptr(p.swap(*this).

template<class Y, class D> void reset(Y * p, D d);

Эффекты: Эквивалент shared_ptr(p, d.swap(*this).

template<class Y, class D, class A> void reset(Y * p, D d, A a);

Эффекты: Эквивалент shared_ptr(p, d, a.swap(*this).

template<class Y> void reset(shared_ptr<Y> const & r, element_type * p); // never throws

Эффекты: Эквивалент shared_ptr(r, p.swap(*this).

indirection

T & operator*() const; // never throws

Требования: T не должны быть типом массива. Сохраненный указатель не должен быть 0.

Возвращает: ссылку на объект, на который указывает сохраненный указатель.

Броски: ничего.

T * operator->() const; // never throws

Требования: T не должны быть типом массива. Сохраненный указатель не должен быть 0.

Возвращает: сохраненный указатель.

Броски: ничего.

element_type & operator[](std::ptrdiff_t i) const; // never throws

Требования: T должны быть типа массива. Сохраненный указатель не должен быть 0. i >= 0. Если T U[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

Эффекты: Обмен содержимого двух интеллектуальных указателей.

Броски: ничего.

swap

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

Последствия: См. описание оператор<.

Броски: ничего.

Free Functions

comparison

template<class T, class U>
  bool operator==(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws

Возврат: a.get() == b.get().

Броски: ничего.

template<class T, class U>
  bool operator!=(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws

Возврат: a.get()!=b.get().

Броски: ничего.

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

Возврат: p.get() == 0.

Броски: ничего.

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

Возврат: p.get()!= 0.

Броски: ничего.

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, которая имеет возможность использоваться стандартной библиотекой.]

get_pointer

template<class T>
  typename shared_ptr<T>::element_type * get_pointer(shared_ptr<T> const & p); // never throws

Возврат: p.get().

Броски: ничего.

Примечания: Предоставляется в качестве помощи для общего программирования. Используется mem_fn.

static_pointer_cast

template<class T, class U>
  shared_ptr<T> static_pointer_cast(shared_ptr<U> const & r); // never throws

Требуется: Выражение static_cast((U*)0) должно быть хорошо сформировано.

Возврат: shared_ptr(r, static_cast::element_type*>(r.get()) ).

Броски: ничего.

Примечания: кажущееся эквивалентным выражение 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) должно быть хорошо сформировано.

Возврат: shared_ptr(r, const_cast::element_type*>(r.get())).

Броски: ничего.

dynamic_pointer_cast

template<class T, class U>
  shared_ptr<T> dynamic_pointer_cast(shared_ptr<U> const & r);

Требуется: Выражение dynamic_cast((U*)0) должно быть хорошо сформировано.

Возврат:

  • Когдаdynamic_cast<typename shared_ptr<T>::element_type*>(r.get())возвращает ненулевое значениеp,shared_ptr<T>(r, p)
  • В противном случаеshared_ptr<T>().

Броски: ничего.

reinterpret_pointer_cast

template<class T, class U>
  shared_ptr<T> reinterpret_pointer_cast(shared_ptr<U> const & r); // never throws

Требуется: Выражение reinterpret_cast((U*)0) должно быть хорошо сформировано.

Возврат: shared_ptr(r, reinterpret_cast::element_type*>(r.get())).

Броски: ничего.

operator<<

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.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-20 00:13:42/0.014550924301147/1