shared_ptr - smart pointers c++11




¿Qué es un puntero inteligente y cuándo debo usar uno? (10)

Aquí está el enlace para respuestas similares: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html

Un puntero inteligente es un objeto que actúa, se ve y se siente como un puntero normal pero ofrece más funcionalidad. En C ++, los punteros inteligentes se implementan como clases de plantilla que encapsulan un puntero y anulan los operadores de puntero estándar. Tienen una serie de ventajas sobre los punteros regulares. Se garantiza que se inicialicen como punteros nulos o punteros a un objeto de montón. Se comprueba la dirección a través de un puntero nulo. Nunca es necesario eliminar. Los objetos se liberan automáticamente cuando el último puntero hacia ellos ha desaparecido. Un problema importante con estos punteros inteligentes es que, a diferencia de los punteros regulares, no respetan la herencia. Los punteros inteligentes no son atractivos para el código polimórfico. A continuación se muestra un ejemplo para la implementación de punteros inteligentes.

Ejemplo:

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

Esta clase implementa un puntero inteligente a un objeto de tipo X. El objeto en sí está ubicado en el montón. Aquí está cómo usarlo:

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

Al igual que otros operadores sobrecargados, p se comportará como un puntero normal,

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

¿Qué es un puntero inteligente y cuándo debo usar uno?


Aquí hay una respuesta simple para estos días de C ++ moderno:

  • ¿Qué es un puntero inteligente?
    Es un tipo cuyos valores se pueden usar como punteros, pero que proporciona la característica adicional de la administración automática de memoria: cuando ya no se usa un puntero inteligente, la memoria a la que apunta está desasignada (consulte también la definición más detallada en Wikipedia ).
  • ¿Cuándo debo usar uno?
    En el código que implica el seguimiento de la propiedad de una parte de la memoria, asignar o desasignar; El puntero inteligente a menudo le ahorra la necesidad de hacer estas cosas explícitamente.
  • Pero, ¿qué puntero inteligente debo usar en cuál de esos casos?
    • Use std::unique_ptr cuando no pretenda mantener varias referencias al mismo objeto. Por ejemplo, utilícelo para un puntero a la memoria que se asigna al ingresar cierto alcance y se desasigna al salir del alcance.
    • Use std::shared_ptr cuando quiera referirse a su objeto desde múltiples lugares, y no desea que se lo desasigne hasta que todas estas referencias hayan desaparecido.
    • Use std::weak_ptr cuando quiera referirse a su objeto desde múltiples lugares, para aquellas referencias para las que está bien ignorar y desasignar (de modo que solo notarán que el objeto desapareció cuando intente desreferencia).
    • No utilice los indicadores de boost:: smart o std::auto_ptr excepto en casos especiales que puede leer si es necesario.
  • ¡Oye, no pregunté cuál usar!
    Ah, pero realmente querías, admitelo.
  • Entonces, ¿cuándo debo usar punteros regulares entonces?
    Principalmente en código que es ajeno a la propiedad de la memoria. Por lo general, esto sería en funciones que obtienen un puntero de otro lugar y no asignan, anulan la asignación o almacenan una copia del puntero que supera su ejecución.

La mayoría de los tipos de punteros inteligentes manejan la eliminación del puntero a objeto por usted. Es muy útil porque ya no tiene que pensar en deshacerse de los objetos manualmente.

Los punteros inteligentes más comúnmente usados ​​son std::tr1::shared_ptr (o boost::shared_ptr ), y, menos comúnmente, std::auto_ptr . Recomiendo el uso regular de shared_ptr .

shared_ptr es muy versátil y se ocupa de una gran variedad de escenarios de eliminación, incluidos los casos en los que los objetos deben "pasar a través de los límites de DLL" (el caso de pesadilla común si se utilizan diferentes libc s entre su código y los DLL).


Las definiciones proporcionadas por Chris, Sergdev y Llyod son correctas. Sin embargo, prefiero una definición más simple, solo para mantener mi vida simple: un puntero inteligente es simplemente una clase que sobrecarga a los operadores -> y * . Lo que significa que su objeto semánticamente parece un puntero, pero puede hacerlo hacer cosas más shared_ptr , incluyendo el conteo de referencias, la destrucción automática, etc. shared_ptr y auto_ptr son suficientes en la mayoría de los casos, pero vienen con su propio conjunto de pequeñas idiosincrasias.


Los punteros inteligentes son aquellos en los que no tiene que preocuparse por la Desasignación de memoria, el Uso compartido de recursos y la Transferencia.

Puede utilizar muy bien este puntero de la misma manera que cualquier asignación funciona en Java. En java Garbage Collector hace el truco, mientras que en Smart Pointers, el truco lo hacen los Destructores.


Me gustaría agregar un punto más a la pregunta anterior, smart pointer std :: shared_ptr no tiene operador de subíndices y no es compatible con la aritmética de ponter, podemos usar get () para obtener un puntero incorporado.


Un puntero inteligente es un objeto que actúa como un puntero, pero además proporciona control sobre la construcción, destrucción, copia, movimiento y eliminación de referencias.

Uno puede implementar su propio puntero inteligente, pero muchas bibliotecas también proporcionan implementaciones de puntero inteligente cada una con diferentes ventajas e inconvenientes.

Por ejemplo, Boost proporciona las siguientes implementaciones de punteros inteligentes:

  • shared_ptr<T> es un puntero a T usa un recuento de referencia para determinar cuándo ya no se necesita el objeto.
  • scoped_ptr<T> es un puntero que se elimina automáticamente cuando queda fuera del alcance. Ninguna asignación es posible.
  • intrusive_ptr<T> es otro puntero de conteo de referencia. Proporciona un mejor rendimiento que shared_ptr , pero requiere que el tipo T proporcione su propio mecanismo de conteo de referencias.
  • weak_ptr<T> es un puntero débil, que trabaja en conjunto con shared_ptr para evitar referencias circulares.
  • shared_array<T> es como shared_ptr , pero para matrices de T
  • scoped_array<T> es como scoped_ptr , pero para matrices de T

Estas son solo una descripciones lineales de cada una y se pueden usar según la necesidad; para más detalles y ejemplos, se puede consultar la documentación de Boost.

Además, la biblioteca estándar de C ++ proporciona tres punteros inteligentes; std::unique_ptr para propiedad única, std::shared_ptr para propiedad compartida y std::weak_ptr . std::auto_ptr existía en C ++ 03 pero ahora está en desuso.


Un puntero inteligente es una clase que envuelve un puntero de C ++ "sin procesar" (o "desnudo"), para administrar la vida útil del objeto al que se apunta. No hay un solo tipo de puntero inteligente, pero todos intentan abstraer un puntero en bruto de una manera práctica.

Los punteros inteligentes deben ser preferidos a los punteros en bruto. Si siente que necesita usar punteros (primero considere si realmente lo hace), normalmente querría usar un puntero inteligente, ya que esto puede aliviar muchos de los problemas con los punteros sin procesar, olvidándose principalmente de eliminar el objeto y la pérdida de memoria.

Con los punteros en bruto, el programador tiene que destruir explícitamente el objeto cuando ya no es útil.

// 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...?

Un puntero inteligente por comparación define una política de cuándo se destruye el objeto. Todavía tienes que crear el objeto, pero ya no tienes que preocuparte por destruirlo.

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

La política más simple en uso implica el alcance del objeto envoltorio del puntero inteligente, como implementado por boost::scoped_ptr o 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.
}

Tenga en cuenta que scoped_ptr instancias de scoped_ptr no se pueden copiar. Esto evita que el puntero se elimine varias veces (incorrectamente). Sin embargo, puede pasar referencias a otras funciones que llame.

Los punteros de ámbito son útiles cuando desea vincular la vida útil del objeto a un bloque de código en particular, o si lo integró como datos miembro dentro de otro objeto, la vida útil de ese otro objeto. El objeto existe hasta que se sale del bloque de código que contiene, o hasta que el objeto que contiene se destruye.

Una política de puntero inteligente más compleja implica referencia al conteo del puntero. Esto permite copiar el puntero. Cuando se destruye la última "referencia" al objeto, el objeto se elimina. Esta política se implementa mediante boost::shared_ptr y 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.

Los punteros contados de referencia son muy útiles cuando la vida útil de su objeto es mucho más complicada y no está vinculada directamente a una sección particular de código u otro objeto.

Hay un inconveniente para hacer referencia a los punteros contados: la posibilidad de crear una referencia colgante:

// 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!

Otra posibilidad es crear referencias circulares:

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!

Para solucionar este problema, tanto Boost como C ++ 11 han definido un weak_ptr para definir una referencia débil (sin shared_ptr ) a un shared_ptr .

ACTUALIZAR

Esta respuesta es bastante antigua, por lo que describe lo que era "bueno" en ese momento, que era punteros inteligentes proporcionados por la biblioteca Boost. Desde C ++ 11, la biblioteca estándar ha proporcionado suficientes tipos de punteros inteligentes, por lo que debería favorecer el uso de std::unique_ptr , std::shared_ptr y std::weak_ptr .

También está std::auto_ptr . Es muy parecido a un puntero de ámbito, excepto que también tiene la capacidad peligrosa "especial" para copiarse, ¡lo que también se transfiere inesperadamente a la propiedad! Está en desuso en los estándares más nuevos, por lo que no debe usarlo. Utilice el std::unique_ptr en std::unique_ptr lugar.

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.

El puntero inteligente es un tipo de puntero con alguna funcionalidad adicional, por ejemplo, desasignación automática de memoria, conteo de referencias, etc.

La introducción pequeña está disponible en la página Punteros inteligentes: ¿qué, por qué, cuál? .

Uno de los tipos simples de puntero inteligente es std::auto_ptr (capítulo 20.4.5 del estándar C ++), que permite desasignar la memoria automáticamente cuando está fuera de alcance y que es más robusto que el uso de punteros simples cuando se lanzan excepciones, aunque menos flexible.

Otro tipo conveniente es boost::shared_ptr que implementa el conteo de referencias y desasigna automáticamente la memoria cuando no queda ninguna referencia al objeto. Esto ayuda a evitar pérdidas de memoria y es fácil de usar para implementar RAII .

El tema se trata en profundidad en el libro "Plantillas de C ++: La guía completa" de David Vandevoorde, Nicolai M. Josuttis , capítulo Capítulo 20. Punteros inteligentes. Algunos temas tratados:


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

En informática, un puntero inteligente es un tipo de datos abstracto que simula un puntero al tiempo que proporciona funciones adicionales, como la recolección automática de basura o la verificación de límites. Estas características adicionales están destinadas a reducir los errores causados ​​por el mal uso de los punteros y al mismo tiempo mantener la eficiencia. Los punteros inteligentes normalmente realizan un seguimiento de los objetos que los apuntan con el propósito de administrar la memoria. El mal uso de los punteros es una fuente importante de errores: la asignación constante, la desasignación y la referencia que debe realizar un programa escrito con punteros hace que sea muy probable que se produzcan algunas pérdidas de memoria. Los punteros inteligentes intentan evitar las fugas de memoria haciendo que la asignación de recursos sea automática: cuando el puntero a un objeto (o el último de una serie de punteros) se destruye, por ejemplo, porque se sale del alcance, el objeto puntiagudo también se destruye.





c++-faq