[C++] Что такое умный указатель, и когда я должен его использовать?


Answers

Вот простой ответ на эти дни современного C ++:

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

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




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

Вы можете очень хорошо использовать этот указатель так же, как любое распределение работает в Java. В java Garbage Collector делает трюк, в то время как в Smart Pointers трюк выполняется Destructors.




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

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

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




Вот ссылка для похожих ответов: 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);



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




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




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

1) Исходные указатели :

T a;  
T * _ptr = &a; 

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

Указатели с данными или адресом const {Прочитать назад}

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

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

  T * const ptr2 ;

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

const T * const ptr3 ; 

Контр-указатель на тип данных const. Это означает, что вы не можете либо переместить указатель, либо не можете изменить указатель типа данных как указатель. т.е. 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, указывающий на объект, выходит из области видимости. Это избавляет от головной боли, связанной с необходимостью удаления объектов, которые вы выделили с помощью нового.

Слабый указатель: помогает справиться с циклической ссылкой, которая возникает при использовании общего указателя. Если у вас есть два объекта, на которые указывают два общих указателя, и есть внутренний общий указатель, указывающий на общий общий указатель, тогда будет циклическая ссылка, и объект не будет быть удалены, если общие указатели выходят за рамки. Чтобы решить эту проблему, измените внутренний член с 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 Спасибо Андре за то, что он указал на этот вопрос.




Links