Различия между unique_ptr и shared_ptr
Возможные дубликаты:
pimpl: shared_ptr или unique_ptr
объяснил smart pointers (boost)
Может ли кто-нибудь объяснить различия между shared_ptr и unique_ptr?
Ответы
Ответ 1
Оба этих класса являются интеллектуальными указателями, а это означает, что они автоматически (в большинстве случаев) освободят объект, на который они указывают, когда этот объект больше не может ссылаться. Разница между ними состоит в том, сколько разных указателей каждого типа может ссылаться на ресурс.
При использовании unique_ptr
может быть не более одного unique_ptr
, указывающего на какой-либо один ресурс. Когда этот unique_ptr
уничтожается, ресурс автоматически возвращается в исходное состояние. Поскольку для любого ресурса может быть только один unique_ptr
, любая попытка сделать копию unique_ptr
приведет к ошибке времени компиляции. Например, этот код является незаконным:
unique_ptr<T> myPtr(new T); // Okay
unique_ptr<T> myOtherPtr = myPtr; // Error: Can't copy unique_ptr
Однако unique_ptr
можно перемещать с использованием новой семантики перемещения:
unique_ptr<T> myPtr(new T); // Okay
unique_ptr<T> myOtherPtr = std::move(myPtr); // Okay, resource now stored in myOtherPtr
Аналогично, вы можете сделать что-то вроде этого:
unique_ptr<T> MyFunction() {
unique_ptr<T> myPtr(/* ... */);
/* ... */
return myPtr;
}
Эта идиома означает: "Я возвращаю вам управляемый ресурс. Если вы явно не зафиксируете возвращаемое значение, тогда ресурс будет очищен. Если вы это сделаете, то теперь у вас есть эксклюзивное право владения этим ресурсом." Таким образом, вы можете думать о unique_ptr
как о более безопасной, лучшей замене для auto_ptr
.
shared_ptr
, с другой стороны, позволяет указывать несколько указателей на данный ресурс. Когда последний shared_ptr
ресурс будет уничтожен, ресурс будет освобожден. Например, этот код совершенно легален:
shared_ptr<T> myPtr(new T); // Okay
shared_ptr<T> myOtherPtr = myPtr; // Sure! Now have two pointers to the resource.
Внутри shared_ptr
использует подсчет ссылок, чтобы отслеживать, сколько указателей ссылается на ресурс, поэтому вам нужно быть осторожным, чтобы не вводить никаких эталонных циклов.
Короче:
- Используйте
unique_ptr
, если вам нужен один указатель на объект, который будет восстановлен, когда этот единственный указатель будет уничтожен.
- Используйте
shared_ptr
, если вам нужно указать несколько указателей на один и тот же ресурс.
Надеюсь, это поможет!
Ответ 2
unique_ptr
- это легкий интеллектуальный указатель выбора, если у вас есть только динамический объект где-то, у которого один потребитель имеет единственную (следовательно, "уникальную" ) ответственность - возможно, класс-оболочку, который должен поддерживать некоторый динамически распределенный объект, unique_ptr
имеет очень мало накладных расходов. Он не копируется, а движимый. Его тип template <typename D, typename Deleter> class unique_ptr;
, поэтому он зависит от параметров шаблона два.
unique_ptr
также означает, что auto_ptr
хотел быть в старом С++, но не мог из-за ограничений этого языка.
shared_ptr
, с другой стороны, совсем другое животное. Очевидное различие заключается в том, что у вас может быть много потребителей, разделяющих ответственность за динамический объект (следовательно, "общий" ), и объект будет уничтожен только тогда, когда все общие указатели исчезнут. Кроме того, вы можете наблюдать слабые указатели, которые будут разумно проинформированы, если общий указатель, за которым они следуют, исчез.
Внутренне shared_ptr
имеет гораздо больше возможностей: существует счетчик ссылок, который обновляется атомарно, чтобы разрешить использование в параллельном коде. Кроме того, существует много распределений, один для внутреннего "контрольного блока" бухгалтерии и другой (часто) для фактического объекта-члена.
Но есть и другая большая разница: тип общих указателей всегда template <typename T> class shared_ptr;
, и это несмотря на то, что вы можете инициализировать его с помощью пользовательских удалений и с помощью пользовательских распределителей. Делектор и распределитель отслеживаются с помощью стирания типов и отправки виртуальных функций, что добавляет к внутреннему весу класса, но имеет огромное преимущество в том, что различные типы общих указателей типа T
совместимы, независимо от удаления и распределения Детали. Таким образом, они действительно выражают концепцию "общей ответственности за T
", не обременяя потребителя деталями!
Оба shared_ptr
и unique_ptr
предназначены для передачи по значению (с очевидным требованием к движению для уникального указателя). Вы также не должны беспокоиться о накладных расходах, поскольку их сила действительно поразительна, но если у вас есть выбор, предпочитайте unique_ptr
и используйте shared_ptr
, если вам действительно нужна общая ответственность.
Ответ 3
unique_ptr
является интеллектуальным указателем, которому принадлежит исключительно объект.
shared_ptr
является умным указателем для совместного использования. Это как copyable
и movable
. Несколько экземпляров интеллектуальных указателей могут владеть одним и тем же ресурсом. Как только последний умный указатель, владеющий ресурсом, выходит из области видимости, ресурс будет освобожден.
Ответ 4
При переносе указателя в unique_ptr
вы не можете иметь несколько копий unique_ptr
. shared_ptr
содержит контрольный счетчик, который подсчитывает количество копий сохраненного указателя. Каждый раз, когда копируется shared_ptr
, этот счетчик увеличивается. Каждый раз, когда a shared_ptr
разрушается, этот счетчик уменьшается. Когда этот счетчик достигнет 0, тогда сохраненный объект будет уничтожен.