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


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


1401


источник


Ответы:


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

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

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

// 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()
{
    {
       boost::scoped_ptr<MyObject> ptr(new MyObject());
       ptr->DoSomethingUseful();
    } // boost::scopted_ptr goes out of scope -- 
      // the MyObject is automatically destroyed.

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

Обратите внимание, что scoped_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 {
   boost::shared_ptr<Owner> other;
};

boost::shared_ptr<Owner> p1 (new Owner());
boost::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,


ОБНОВИТЬ

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

Есть также std::auto_ptr, Он очень похож на указатель с областью действия, за исключением того, что он также имеет «специальную» опасную способность, которую можно скопировать, что также неожиданно передает право собственности! Он устарел в новейших стандартах, поэтому вы не должны его использовать. Использовать std::unique_ptrвместо.

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.

1612



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

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

157



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

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

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

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

Тема подробно освещена в книге «C ++ Templates: The Complete Guide» Дэвида Вандевоорда, Николай М. Йосуттис , глава Глава 20. Умные указатели. Некоторые затронутые темы:

  • Защита от исключений
  • Держатели, (примечание, станд :: auto_ptr это реализация такого типа интеллектуального указателя)
  • Инициализация ресурсов (Это часто используется для безопасного управления ресурсами на C ++)
  • Ограничения владельца
  • Подсчет ссылок
  • Параллельный доступ к счетчикам
  • Разрушение и освобождение

96



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


33



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

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

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

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

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

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

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


25



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

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

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


14



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

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

Например, Увеличение предоставляет следующие реализации интеллектуальных указателей:

  • 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, но теперь устарел.


14



Here is the Link for similar answers : http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html

A smart pointer is an object that acts, looks and feels like a normal pointer but offers more functionality. In C++, smart pointers are implemented as template classes that encapsulate a pointer and override standard pointer operators. They have a number of advantages over regular pointers. They are guaranteed to be initialized as either null pointers or pointers to a heap object. Indirection through a null pointer is checked. No delete is ever necessary. Objects are automatically freed when the last pointer to them has gone away. One significant problem with these smart pointers is that unlike regular pointers, they don't respect inheritance. Smart pointers are unattractive for polymorphic code. Given below is an example for the implementation of smart pointers.

Example:

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:
               //...
};

This class implement a smart pointer to an object of type X. The object itself is located on the heap. Here is how to use it:

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

Like other overloaded operators, p will behave like a regular pointer,

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

9



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.


8



Let T be a class in this tutorial Pointers in C++ can be divided into 3 types :

1) Raw pointers :

T a;  
T * _ptr = &a; 

They hold a memory address to a location in memory. Use with caution , as programs become complex hard to keep track.

Pointers with const data or address { Read backwards }

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

Pointer to a data type T which is a const. Meaning you cannot change the data type using the pointer. ie *ptr1 = 19 ; will not work. But you can move the pointer. ie ptr1++ , ptr1-- ; etc will work. Read backwards : pointer to type T which is const

  T * const ptr2 ;

A const pointer to a data type T . Meaning you cannot move the pointer but you can change the value pointed to by the pointer. ie *ptr2 = 19 will work but ptr2++ ; ptr2-- etc will not work. Read backwards : const pointer to a type T

const T * const ptr3 ; 

A const pointer to a const data type T . Meaning you cannot either move the pointer nor can you change the data type pointer to be the pointer. ie . ptr3-- ; ptr3++ ; *ptr3 = 19; will not work

3) Smart Pointers : { #include <memory> }

Shared Pointer:

  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

Implemented using reference counting to keep track of how many " things " point to the object pointed to by the pointer. When this count goes to 0 , the object is automatically deleted , ie objected is deleted when all the share_ptr pointing to the object goes out of scope. This gets rid of the headache of having to delete objects which you have allocated using new.

Weak Pointer : Helps deal with cyclic reference which arises when using Shared Pointer If you have two objects pointed to by two shared pointers and there is an internal shared pointer pointing to each others shared pointer then there will be a cyclic reference and the object will not be deleted when shared pointers go out of scope. To solve this , change the internal member from a shared_ptr to weak_ptr. Note : To access the element pointed to by a weak pointer use lock() , this returns a 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

See : When is std::weak_ptr useful?

Unique Pointer : Light weight smart pointer with exclusive ownership. Use when pointer points to unique objects without sharing the objects between the pointers.

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 

To change the object pointed to by the unique ptr , use move semantics

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 

References : They can essentially be though of as const pointers, ie a pointer which is const and cannot be moved with better syntax.

See : What are the differences between a pointer variable and a reference variable in 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 

Reference : https://www.youtube.com/channel/UCEOGtxYTB6vo6MQ-WQ9W_nQ Thanks to Andre for pointing out this question.


2