Что такое умный указатель и когда его использовать?

Что такое умный указатель и когда мне его использовать?

Ответьте на этот вопрос: <br> Умные указатели: или кто владеет вами, детка

Martin York 20.09.2008 04:32

Две отличные статьи по теме: - Умные указатели - что, почему, что? - Гуру недели # 25

Lazer 25.06.2010 23:15

Вот (бесплатная) глава Александреску о мельчайших подробностях создания интеллектуальных указателей разных типов: informit.com/articles/article.aspx?p=31529 В своей реализации он использует аргументы шаблона как «политики», чтобы указать, какие атрибуты он хочет (например, подсчет ссылок), тогда как стандартная библиотека использует отдельные классы. Обратите внимание, что он также писал до того, как стали доступны ссылки на rvalue, чтобы сделать возможным что-то вроде std :: unique_ptr.

metal 19.03.2013 20:30

Обратите внимание, что реализация std :: auto_ptr в Visual Studio 2005 ужасно нарушена. <br> http://connect.microsoft.com/VisualStudio/feedback/ViewF‌ eedback.aspx? Feedbac‌ kID = 98871 <br> http://connect.microsoft.com/VisualStudio/feedback/ViewFeedb‌ ack.aspx? FeedbackID = ‌ 101842 Используйте вместо них повышающие.

Richard 21.09.2008 14:14

Я хотел бы добавить еще один момент к вышеупомянутому вопросу, интеллектуальный указатель std :: shared_ptr не имеет оператора индекса и не поддерживает арифметику понтера, мы можем использовать get () для получения встроенного указателя.

suresh m 07.02.2018 16:57
Он был добавлен в C++ 17, but is not guaranteed to work for anything but plain arrays.
HolyBlackCat 07.02.2018 17:00
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1 924
6
609 917
14
Перейти к ответу Данный вопрос помечен как решенный

Ответы 14

http://en.wikipedia.org/wiki/Smart_pointer

In computer science, a smart pointer is an abstract data type that simulates a pointer while providing additional features, such as automatic garbage collection or bounds checking. These additional features are intended to reduce bugs caused by the misuse of pointers while retaining efficiency. Smart pointers typically keep track of the objects that point to them for the purpose of memory management. The misuse of pointers is a major source of bugs: the constant allocation, deallocation and referencing that must be performed by a program written using pointers makes it very likely that some memory leaks will occur. Smart pointers try to prevent memory leaks by making the resource deallocation automatic: when the pointer to an object (or the last in a series of pointers) is destroyed, for example because it goes out of scope, the pointed object is destroyed too.

Умный указатель похож на обычный (типизированный) указатель, например char *, за исключением случаев, когда сам указатель выходит за пределы области видимости, тогда то, на что он указывает, также удаляется. Вы можете использовать его как обычный указатель, используя «->», но не если вам нужен фактический указатель на данные. Для этого вы можете использовать «& * ptr».

Это полезно для:

  • Объекты, которые должны быть выделены с помощью new, но которые вы хотели бы иметь такое же время жизни, как что-то в этом стеке. Если объекту назначен интеллектуальный указатель, они будут удалены, когда программа выйдет из этой функции / блока.

  • Члены данных классов, так что при удалении объекта все принадлежащие ему данные также удаляются без какого-либо специального кода в деструкторе (вам нужно быть уверенным, что деструктор виртуальный, что почти всегда хорошо) .

Вы можете нет использовать интеллектуальный указатель, когда:

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

Смотрите также:

Большинство видов интеллектуальных указателей обрабатывают удаление объекта-указателя за вас. Это очень удобно, потому что вам больше не нужно думать об утилизации объектов вручную.

Чаще всего используются интеллектуальные указатели std::tr1::shared_ptr (или boost::shared_ptr) и, реже, std::auto_ptr. Рекомендую регулярно использовать shared_ptr.

shared_ptr очень универсален и имеет дело с большим количеством сценариев утилизации, включая случаи, когда объекты необходимо «передать через границы DLL» (общий кошмар, если между вашим кодом и DLL используются разные libc).

умный указатель - это указательоподобный тип с некоторыми дополнительными функциями, например автоматическое освобождение памяти, подсчет ссылок и т. д.

Небольшое вступление доступно на странице Умные указатели - что, почему, что?.

Одним из простых типов интеллектуальных указателей является std::auto_ptr (глава 20.4.5 стандарта C++), который позволяет автоматически освобождать память, когда она выходит за пределы области видимости, и который является более надежным, чем использование простого указателя при возникновении исключений, хотя и менее гибким.

Другой удобный тип - boost::shared_ptr, который реализует подсчет ссылок и автоматически освобождает память, когда не остается ссылок на объект. Это помогает избежать утечек памяти и легко использовать для реализации RAII.

Эта тема подробно рассматривается в книге «Шаблоны C++: полное руководство» Дэвида Вандевурда, Николая М. Йосаттиса, глава 20. Интеллектуальные указатели. Некоторые затронутые темы:

Предупреждение std::auto_ptr устарел и крайне не рекомендуется, так как вы можете случайно передать право собственности. - C++ 11 устраняет необходимость в Boost, используйте: std::unique_ptr, std::shared_ptr и std::weak_ptr

ninMonkey 12.06.2019 16:38
Ответ принят как подходящий

ОБНОВИТЬ

Этот ответ довольно старый и поэтому описывает то, что было «хорошо» в то время, а именно интеллектуальные указатели, предоставляемые библиотекой Boost. Начиная с C++ 11, стандартная библиотека предоставляет достаточное количество типов интеллектуальных указателей, поэтому вам следует отдать предпочтение использованию std::unique_ptr, std::shared_ptr и std::weak_ptr.

Еще был std::auto_ptr. Он был очень похож на указатель с ограниченной областью видимости, за исключением того, что он также обладал «особой» опасной способностью копировать, что также неожиданно передает право собственности. Он был объявлен устаревшим в C++ 11 и удален в C++ 17., поэтому использовать его не стоит.

std::auto_ptr<MyObject> p1 (new MyObject());
std::auto_ptr<MyObject> p2 = p1; // Copy and transfer ownership. 
                                 // p1 gets set to empty!
p2->DoSomething(); // Works.
p1->DoSomething(); // Oh oh. Hopefully raises some NULL pointer exception.

СТАРЫЙ ОТВЕТ

Умный указатель - это класс, который обертывает «необработанный» (или «пустой») указатель C++, чтобы управлять временем жизни объекта, на который указывает. Не существует единого типа интеллектуального указателя, но все они пытаются на практике абстрагировать необработанный указатель.

Умные указатели должны быть предпочтительнее необработанных указателей. Если вы чувствуете, что вам нужно использовать указатели (сначала подумайте, используете ли вы В самом деле), вы обычно хотите использовать интеллектуальный указатель, поскольку это может облегчить многие проблемы с необработанными указателями, в основном забывая удалить объект и утечку памяти.

С необработанными указателями программист должен явно уничтожить объект, когда он больше не используется.

// Need to create the object to achieve some goal
MyObject* ptr = new MyObject(); 
ptr->DoSomething(); // Use the object in some way
delete ptr; // Destroy the object. Done with it.
// Wait, what if DoSomething() raises an exception...?

Умный указатель путем сравнения определяет политику в отношении того, когда объект уничтожается. Вам все еще нужно создать объект, но вам больше не нужно беспокоиться о его разрушении.

SomeSmartPtr<MyObject> ptr(new MyObject());
ptr->DoSomething(); // Use the object in some way.

// Destruction of the object happens, depending 
// on the policy the smart pointer class uses.

// Destruction would happen even if DoSomething() 
// raises an exception

Самая простая в использовании политика включает в себя область объекта-оболочки интеллектуального указателя, например, реализованную boost::scoped_ptr или std::unique_ptr.

void f()
{
    {
       std::unique_ptr<MyObject> ptr(new MyObject());
       ptr->DoSomethingUseful();
    } // ptr goes out of scope -- 
      // the MyObject is automatically destroyed.

    // ptr->Oops(); // Compile error: "ptr" not defined
                    // since it is no longer in scope.
}

Обратите внимание, что экземпляры std::unique_ptr не могут быть скопированы. Это предотвращает многократное (неправильное) удаление указателя. Однако вы можете передавать ссылки на него другим функциям, которые вы вызываете.

std::unique_ptr полезны, когда вы хотите связать время жизни объекта с конкретным блоком кода или, если вы встроили его как данные члена внутри другого объекта, время жизни этого другого объекта. Объект существует до тех пор, пока содержащий блок кода не будет завершен, или пока содержащий объект не будет уничтожен сам.

Более сложная политика интеллектуального указателя включает подсчет ссылок на указатель. Это позволяет копировать указатель. Когда последняя «ссылка» на объект уничтожается, объект удаляется. Эта политика реализуется boost::shared_ptr и std::shared_ptr.

void f()
{
    typedef std::shared_ptr<MyObject> MyObjectPtr; // nice short alias
    MyObjectPtr p1; // Empty

    {
        MyObjectPtr p2(new MyObject());
        // There is now one "reference" to the created object
        p1 = p2; // Copy the pointer.
        // There are now two references to the object.
    } // p2 is destroyed, leaving one reference to the object.
} // p1 is destroyed, leaving a reference count of zero. 
  // The object is deleted.

Указатели с подсчетом ссылок очень полезны, когда время жизни вашего объекта намного сложнее и не привязано напрямую к конкретному разделу кода или другому объекту.

У указателей с подсчетом ссылок есть один недостаток - возможность создания висячей ссылки:

// Create the smart pointer on the heap
MyObjectPtr* pp = new MyObjectPtr(new MyObject())
// Hmm, we forgot to destroy the smart pointer,
// because of that, the object is never destroyed!

Другая возможность - создание циклических ссылок:

struct Owner {
   std::shared_ptr<Owner> other;
};

std::shared_ptr<Owner> p1 (new Owner());
std::shared_ptr<Owner> p2 (new Owner());
p1->other = p2; // p1 references p2
p2->other = p1; // p2 references p1

// Oops, the reference count of of p1 and p2 never goes to zero!
// The objects are never destroyed!

Чтобы обойти эту проблему, и Boost, и C++ 11 определили weak_ptr для определения слабой (неучтенной) ссылки на shared_ptr.

Вы имеете в виду std::auto_ptr<MyObject> p1 (new MyObject()); вместо std::auto_ptr<MyObject> p1 (new Owner());?

Mateen Ulhaq 17.07.2011 03:06

Откуда взялось пространство имен tr1? Это в стандартной библиотеке?

galymzhan 08.05.2012 11:39

Возможно, придирка к другому замечательному комментарию, но было бы здорово, если бы он включал что-то о памяти и накладных расходах процессора, вызванных умным указателем; просто так можно сказать, что он включает всю информацию

errah 13.06.2012 01:22

Отличный ответ. Было бы неплохо, если бы его обновили для C++ 11. Я нашел этот ответ в поисках информации о новом стандарте 11, и было бы неплохо, если бы будущие посетители могли найти обновленную информацию. Я знаю, что auto_ptr устарел. Я считаю, что shated_ptr и weak_ptr существуют, как описано, и я думаю, что scoped_ptr теперь является unique_ptr в стандарте. Если это правда, можно ли обновить этот ответ?

SaulBack 12.09.2012 00:50

Не существует такой вещи, как std :: tr1 :: scoped_ptr, только boost :: scoped_ptr.

metal 19.03.2013 20:33

Не могли бы вы подробнее рассказать о weak_ptr и о том, как он решит проблему циркулярных ссылок?

mbadawi23 15.09.2013 21:14

Сказать, что возможность создания висячей ссылки является недостатком указателей с подсчетом ссылок, абсолютно безумие. Возможные висячие ссылки являются недостатком любой указатель C++. Фактически, это именно этот недостаток, интеллектуальные указатели которого предназначены для облегчить.

Michael Dorst 14.08.2014 01:59

Если вы объявляете указатель на интеллектуальный указатель (как это было сделано в примере), вы сознательно отказываетесь от всех преимуществ интеллектуального указателя. Это не недостаток или недостаток дизайна, это самый идиотский способ использования, который только можно вообразить.

Michael Dorst 14.08.2014 02:02

const std::auto_ptr безопасен в использовании, если вы застряли на C++ 03. Я довольно часто использовал его для шаблона pimpl, пока не получил доступ к C++ 11.

Toby Speight 17.09.2015 14:55

«в основном забывает удалить объект и утекает память». или, что еще хуже, удаляя его слишком рано и повреждая случайную память и вызывая сбой или неправильные результаты в общем несвязанном фрагменте кода ...

plugwash 21.10.2015 03:34

@Lloyd в третьем последнем фрагменте кода (озаглавленном «Есть один недостаток у указателей с подсчетом ссылок - возможность создания висячей ссылки:»). Что, если я сделаю общий указатель на общий указатель? .ie. std::shared_ptr<MyObjectPtr> pp не решит ли проблему с зависшим указателем, если я забуду удалить pp?

Rohit Rawat 09.02.2017 09:38

«Умные указатели должны быть предпочтительнее необработанных указателей». Это не всегда верно. Для владение следует отдавать предпочтение интеллектуальным указателям. Передача необработанного указателя для использования, когда он может быть нулевым (и поэтому ссылка не подходит), нормально.

xaxxon 24.07.2017 04:00

Обратите внимание, что в C++ 14 теперь есть std::make_unique (en.cppreference.com/w/cpp/memory/unique_ptr/make_unique) для создания std::unique_ptr (en.cppreference.com/w/cpp/memory/unique_ptr) вместо того, чтобы делать это явно.

Gabriel Staples 21.12.2017 23:06

"Умные указатели предпочтительнее необработанных указателей" Означает ли это, что от функций-членов следует отказаться?

curiousguy 14.11.2019 19:20

В случае автоматического удаления, когда уникальный указатель на объект выходит за пределы области видимости, возникает вопрос: почему бы просто не использовать стек? Вместо std::unique_ptr<MyObject> ptr(new MyObject()); внутри блока с областью видимости просто сделайте MyObject() myobj; внутри блока с областью видимости и готово! Когда myobj выходит за пределы области видимости, он автоматически удаляется из стека! Итак, зачем вообще здесь динамически размещать в куче? Пожалуйста, обсудите это в своем ответе.

Gabriel Staples 26.02.2020 22:32

Вопрос, который я только что задал, относительно моего комментария выше: stackoverflow.com/questions/60421416/…

Gabriel Staples 26.02.2020 22:44

std::unique_ptr находится в заголовочном файле <memory>. +1, если вы это искали: D

NAND 15.05.2020 02:04

Определения, предоставленные Крисом, Сергдевым и Ллёдом, верны. Однако я предпочитаю более простое определение, чтобы не усложнять себе жизнь: Умный указатель - это просто класс, который перегружает операторы -> и *. Это означает, что ваш объект семантически выглядит как указатель, но вы можете заставить его делать более крутые вещи, включая подсчет ссылок, автоматическое уничтожение и т. д. shared_ptr и auto_ptr достаточны в большинстве случаев, но имеют свой собственный набор небольших особенностей.

Умный указатель - это объект, который действует как указатель, но дополнительно обеспечивает контроль над построением, разрушением, копированием, перемещением и разыменованием.

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

Например, Способствовать росту предоставляет следующие реализации интеллектуального указателя:

  • shared_ptr<T> - это указатель на T, использующий счетчик ссылок, чтобы определить, когда объект больше не нужен.
  • scoped_ptr<T> - это указатель, автоматически удаляемый, когда он выходит за пределы области видимости. Назначение невозможно.
  • intrusive_ptr<T> - еще один указатель подсчета ссылок. Он обеспечивает лучшую производительность, чем shared_ptr, но требует, чтобы тип T имел собственный механизм подсчета ссылок.
  • weak_ptr<T> - слабый указатель, работающий вместе с shared_ptr, чтобы избежать циклических ссылок.
  • shared_array<T> похож на shared_ptr, но для массивов T.
  • scoped_array<T> похож на scoped_ptr, но для массивов T.

Это всего лишь одно линейное описание каждого из них, и их можно использовать по мере необходимости, для получения более подробной информации и примеров можно посмотреть документацию Boost.

Кроме того, стандартная библиотека C++ предоставляет три интеллектуальных указателя; std::unique_ptr для уникального владения, std::shared_ptr для совместного владения и std::weak_ptr. std::auto_ptr существовал в C++ 03, но теперь не рекомендуется.

Пожалуйста, объясните, почему scoped_ptr не похож на локально объявленный const unique_ptr, который также удаляется при выходе из области видимости.

einpoklum 30.12.2015 00:54

Вот ссылка на похожие ответы: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html

Умный указатель - это объект, который действует, выглядит и ощущается как обычный указатель, но предлагает больше функциональных возможностей. В C++ интеллектуальные указатели реализованы как классы шаблонов, которые инкапсулируют указатель и переопределяют стандартные операторы указателя. У них есть ряд преимуществ перед обычными указателями. Гарантируется, что они инициализируются либо как нулевые указатели, либо как указатели на объект кучи. Проверяется косвенное обращение через нулевой указатель. Удаление не требуется. Объекты автоматически освобождаются, когда исчезает последний указатель на них. Одна из существенных проблем этих интеллектуальных указателей заключается в том, что в отличие от обычных указателей они не уважают наследование. Умные указатели непривлекательны для полиморфного кода. Ниже приведен пример реализации интеллектуальных указателей.

Пример:

template <class X>
class smart_pointer
{
          public:
               smart_pointer();                          // makes a null pointer
               smart_pointer(const X& x)            // makes pointer to copy of x

               X& operator *( );
               const X& operator*( ) const;
               X* operator->() const;

               smart_pointer(const smart_pointer <X> &);
               const smart_pointer <X> & operator =(const smart_pointer<X>&);
               ~smart_pointer();
          private:
               //...
};

Этот класс реализует интеллектуальный указатель на объект типа X. Сам объект находится в куче. Вот как им пользоваться:

smart_pointer <employee> p= employee("Harris",1333);

Как и другие перегруженные операторы, p будет вести себя как обычный указатель,

cout<<*p;
p->raise_salary(0.5);

Вот простой ответ для наших дней современного C++ (C++ 11 и новее):

  • "Что такое умный указатель?"
    Это тип, значения которого можно использовать как указатели, но который обеспечивает дополнительную функцию автоматического управления памятью: когда интеллектуальный указатель больше не используется, память, на которую он указывает, освобождается (см. Также более подробное определение в Википедии).
  • "Когда я должен использовать один?"
    В коде, который включает отслеживание владения частью памяти, выделение или освобождение памяти; умный указатель часто избавляет вас от необходимости делать эти вещи явно.
  • «Но какой умный указатель мне следует использовать в каком из этих случаев?»
    • Используйте std::unique_ptr, если вы хотите, чтобы ваш объект существовал до тех пор, пока существует единственная ссылка-владелец на него. Например, используйте его для указателя на память, которая выделяется при входе в некоторую область и освобождается при выходе из области.
    • Используйте std::shared_ptr, когда вы действительно хотите ссылаться на свой объект из нескольких мест - и не хотите, чтобы ваш объект был освобожден от размещения, пока все эти ссылки сами не исчезнут.
    • Используйте std::weak_ptr, когда вы действительно хотите ссылаться на свой объект из нескольких мест - для тех ссылок, для которых можно игнорировать и освобождать (чтобы они просто отметили, что объект исчез, когда вы попытаетесь разыменовать).
    • Не используйте интеллектуальные указатели boost:: или std::auto_ptr, за исключением особых случаев, о которых вы можете прочитать при необходимости.
  • "Эй, я не спрашивал, какой использовать!"
    Ах, но ты очень хотел, признай это.
  • «Так когда же мне тогда использовать обычные указатели?»
    В основном в коде, который не обращает внимания на владение памятью. Обычно это происходит в функциях, которые получают указатель откуда-то еще и не выделяют, не освобождают выделение и не хранят копию указателя, которая превышает срок их выполнения.

Стоит отметить, что, хотя интеллектуальные (владеющие) указатели помогают в правильном управлении памятью, необработанные (не владеющие) указатели по-прежнему полезны для других организационных целей в структурах данных. Херб Саттер сделал отличную презентацию по этому поводу на CppCon 2016, которую вы можете увидеть на YouTube: Свобода утечек в C++ ... По умолчанию.

wiktor.wandachowicz 14.11.2016 02:22

@ wiktor.wandachowicz T* соответствует std::unique_ptr<T>, что std::weak_ptr<T> соответствует std::shared_ptr<T>

Caleth 17.09.2019 15:50

@Caleth: Нет, я бы так не сказал.

einpoklum 17.09.2019 17:27

Пусть T будет классом в этом руководстве Указатели в C++ можно разделить на 3 типа:

1) Необработанные указатели:

T a;  
T * _ptr = &a; 

Они хранят адрес памяти в месте в памяти. Используйте с осторожностью, так как программы становятся сложными для отслеживания.

Указатели с константными данными или адресом {читать в обратном направлении}

T a ; 
const T * ptr1 = &a ; 
T const * ptr1 = &a ;

Указатель на тип данных T, который является константой. Это означает, что вы не можете изменить тип данных с помощью указателя. т.е. *ptr1 = 19; не будет работать. Но вы можете переместить указатель. т.е. ptr1++ , ptr1--; и т. д. будут работать. Чтение в обратном направлении: указатель на тип T, который является const

  T * const ptr2 ;

Константный указатель на тип данных T. Это означает, что вы не можете перемещать указатель, но можете изменить значение, на которое указывает указатель. т.е. *ptr2 = 19 будет работать, но ptr2++ ; ptr2-- и т. д. работать не будет. Чтение в обратном направлении: константный указатель на тип T

const T * const ptr3 ; 

Константный указатель на константный тип данных T. Это означает, что вы не можете ни перемещать указатель, ни изменить указатель типа данных на указатель. т.е. ptr3-- ; ptr3++ ; *ptr3 = 19; работать не будет

3) Умные указатели: {#include <memory>}

Общий указатель:

  T a ; 
     //shared_ptr<T> shptr(new T) ; not recommended but works 
     shared_ptr<T> shptr = make_shared<T>(); // faster + exception safe

     std::cout << shptr.use_count() ; // 1 //  gives the number of " 
things " pointing to it. 
     T * temp = shptr.get(); // gives a pointer to object

     // shared_pointer used like a regular pointer to call member functions
      shptr->memFn();
     (*shptr).memFn(); 

    //
     shptr.reset() ; // frees the object pointed to be the ptr 
     shptr = nullptr ; // frees the object 
     shptr = make_shared<T>() ; // frees the original object and points to new object

Реализовано с использованием подсчета ссылок для отслеживания количества «вещей», указывающих на объект, на который указывает указатель. Когда этот счетчик становится равным 0, объект автоматически удаляется, т. Е. Объект objected удаляется, когда все share_ptr, указывающее на объект, выходит за пределы области видимости. Это избавляет от головной боли, связанной с удалением объектов, которые вы разместили с помощью new.

Слабый указатель: Помогает справиться с циклическими ссылками, возникающими при использовании общего указателя. Если у вас есть два объекта, на которые указывают два общих указателя, и есть внутренний общий указатель, указывающий на общий указатель друг друга, тогда будет циклическая ссылка, и объект не будет удален, когда общие указатели выйдут за пределы области видимости. Чтобы решить эту проблему, измените внутренний член с shared_ptr на weak_ptr. Примечание. Чтобы получить доступ к элементу, на который указывает слабый указатель, используйте lock (), он возвращает weak_ptr.

T a ; 
shared_ptr<T> shr = make_shared<T>() ; 
weak_ptr<T> wk = shr ; // initialize a weak_ptr from a shared_ptr 
wk.lock()->memFn() ; // use lock to get a shared_ptr 
//   ^^^ Can lead to exception if the shared ptr has gone out of scope
if (!wk.expired()) wk.lock()->memFn() ;
// Check if shared ptr has gone out of scope before access

См .: Когда полезен std :: weak_ptr?

Уникальный указатель: Легкая интеллектуальная указка с эксклюзивным владением. Используйте, когда указатель указывает на уникальные объекты, не разделяя объекты между указателями.

unique_ptr<T> uptr(new T);
uptr->memFn(); 

//T * ptr = uptr.release(); // uptr becomes null and object is pointed to by ptr
uptr.reset() ; // deletes the object pointed to by uptr 

Чтобы изменить объект, на который указывает уникальный ptr, используйте семантику перемещения

unique_ptr<T> uptr1(new T);
unique_ptr<T> uptr2(new T);
uptr2 = std::move(uptr1); 
// object pointed by uptr2 is deleted and 
// object pointed by uptr1 is pointed to by uptr2
// uptr1 becomes null 

Рекомендации : По сути, они могут быть константными указателями, т. Е. Константными указателями, которые нельзя переместить с помощью лучшего синтаксиса.

См .: В чем разница между переменной-указателем и переменной-ссылкой в ​​C++?

r-value reference : reference to a temporary object   
l-value reference : reference to an object whose address can be obtained
const reference : reference to a data type which is const and cannot be modified 

Ссылка : https://www.youtube.com/channel/UCEOGtxYTB6vo6MQ-WQ9W_nQ Спасибо Андре за указание на этот вопрос.

Умные указатели - это те, в которых вам не нужно беспокоиться о де-распределении памяти, совместном использовании ресурсов и передаче.

Вы можете использовать этот указатель точно так же, как любое выделение памяти в Java. В java сборщик мусора делает свое дело, в то время как в смарт-указателях это делается с помощью деструкторов.

Умный указатель - это класс, оболочка обычного указателя. В отличие от обычных указателей, жизненный цикл интеллектуальной точки основан на подсчете ссылок (сколько раз присваивается объекту интеллектуального указателя). Таким образом, всякий раз, когда интеллектуальный указатель назначается другому, счетчик внутренних ссылок плюс плюс. И всякий раз, когда объект выходит за пределы области видимости, счетчик ссылок минус минус.

Автоматический указатель хоть и выглядит похожим, но полностью отличается от умного указателя. Это удобный класс, который освобождает ресурс всякий раз, когда объект автоматического указателя выходит за пределы области видимости переменной. В некоторой степени он заставляет указатель (на динамически выделяемую память) работать аналогично переменной стека (статически выделяемой во время компиляции).

Существующие ответы хороши, но не охватывают, что делать, если умный указатель не является (полным) ответом на проблему, которую вы пытаетесь решить.

Среди прочего (хорошо объяснено в других ответах) использование интеллектуального указателя является возможным решением Как нам использовать абстрактный класс в качестве возвращаемого типа функции?, который был отмечен как дубликат этого вопроса. Однако первый вопрос, который следует задать, если возникнет соблазн указать абстрактный (или фактически любой) базовый класс в качестве возвращаемого типа в C++, - это «что вы на самом деле имеете в виду?». В документации библиотека контейнеров ускоренных указателей есть хорошее обсуждение (с дополнительными ссылками) идиоматического объектно-ориентированного программирования на C++ (и его отличие от других языков). Таким образом, в C++ вы должны думать о владении. Какие умные указатели помогают вам, но не являются единственным решением или всегда полным решением (они не дают вам полиморфной копии) и не всегда являются решением, которое вы хотите представить в своем интерфейсе (а возврат функции звучит ужасно очень нравится интерфейс). Например, может быть достаточно вернуть ссылку. Но во всех этих случаях (интеллектуальный указатель, контейнер указателя или просто возврат ссылки) вы изменили возврат с ценить на некоторую форму ссылка. Если вам действительно нужна копия, вам может потребоваться добавить больше шаблонной «идиомы» или перейти от идиоматического (или другого) ООП в C++ к более универсальному полиморфизму с использованием таких библиотек, как Adobe Poly или Boost.TypeErasure.

Что такое умный указатель.

Длинная версия, в принципе:

https://web.stanford.edu/class/archive/cs/cs106l/cs106l.1192/lectures/lecture15/15_RAII.pdf

Современная идиома C++:

RAII: Resource Acquisition Is Initialization.

● When you initialize an object, it should already have 
  acquired any resources it needs (in the constructor).


● When an object goes out of scope, it should release every 
  resource it is using (using the destructor).

ключевой момент:

● There should never be a half-ready or half-dead object.
● When an object is created, it should be in a ready state.
● When an object goes out of scope, it should release its resources. 
● The user shouldn’t have to do anything more. 

Необработанные указатели нарушают RAII: пользователю необходимо удалить вручную, когда указатели выходят за пределы области видимости.

Решение RAII:

Have a smart pointer class:
● Allocates the memory when initialized
● Frees the memory when destructor is called
● Allows access to underlying pointer

Для умного указателя нужно скопировать и поделиться, используйте shared_ptr:

● use another memory to store Reference counting and shared.
● increment when copy, decrement when destructor.
● delete memory when Reference counting is 0. 
  also delete memory that store Reference counting.

для умного указателя, не владеющего необработанным указателем, используйте weak_ptr:

● not change Reference counting.

shared_ptr использование:

correct way:
std::shared_ptr<T> t1 = std::make_shared<T>(TArgs);
std::shared_ptr<T> t2 = std::shared_ptr<T>(new T(Targs));

wrong way:
T* pt = new T(TArgs); // never exposure the raw pointer
shared_ptr<T> t1 = shared_ptr<T>(pt);
shared_ptr<T> t2 = shared_ptr<T>(pt);

Всегда избегайте использования необработанного указателя.

Для сценария, в котором необходимо использовать необработанный указатель:

https://stackoverflow.com/a/19432062/2482283

Для необработанного указателя, который не равен nullptr, используйте ссылку.

not use T*
use T&  

Для дополнительной ссылки, которая может быть nullptr, используйте необработанный указатель, что означает:

T* pt; is optional reference and maybe nullptr.
Not own the raw pointer, 
Raw pointer is managed by some one else.
I only know that the caller is sure it is not released now.

Другие вопросы по теме