Pregunta ¿Qué es un puntero inteligente y cuándo debería usar uno?


¿Qué es un puntero inteligente y cuándo debería usar uno?


1427
2017-09-20 00:09


origen


Respuestas:


Un puntero inteligente es una clase que envuelve un puntero C ++ "en bruto" (o "simple") 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 sin procesar de una manera práctica.

Los punteros inteligentes deberían preferirse a los punteros sin formato. Si cree que necesita utilizar punteros (primero considere si De Verdad do), normalmente querrías usar un puntero inteligente ya que esto puede aliviar muchos de los problemas con los punteros crudos, olvidando principalmente eliminar el objeto y la pérdida de memoria.

Con punteros sin formato, 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 en comparación define una política sobre cuándo se destruye el objeto. Aún debe crear el objeto, pero ya no tiene que preocuparse 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 involucra el alcance del objeto envoltorio del puntero inteligente, tal como el 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 las instancias no pueden ser copiadas Esto evita que el puntero se elimine varias veces (incorrectamente). Sin embargo, puede pasarle referencias a otras funciones que llame.

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

Una política de puntero inteligente más compleja implica referencia contando el puntero. Esto permite copiar el puntero. Cuando se destruye la última "referencia" al objeto, el objeto se elimina. Esta política es implementada por 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 del código oa otro objeto.

Hay un inconveniente para hacer referencia a los apuntadores 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 evitar este problema, tanto Boost como C ++ 11 han definido un weak_ptr para definir una referencia débil (sin contar) a un shared_ptr.


ACTUALIZAR

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

También hay 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 transfiere inesperadamente la propiedad. Está obsoleto en los estándares más nuevos, por lo que no debe usarlo. Utilizar el std::unique_ptr en 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.

1640
2017-09-20 00:48



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

  • ¿Qué es un puntero inteligente? 
    Es un tipo de valor que se puede utilizar como un puntero, pero proporciona la característica adicional de la gestión automática de la memoria: cuando el puntero ya no está en uso, la memoria a la que apunta es desasignada (ver también la definición más detallada en Wikipedia)
  • ¿Cuándo debería usar uno? 
    En el código que implica el seguimiento de la propiedad de una pieza de memoria, la asignación o la desasignación; el puntero inteligente a menudo le ahorra la necesidad de hacer estas cosas de forma explícita.
  • Pero, ¿qué puntero inteligente debería usar en cuál de esos casos?
    • Utilizar std::unique_ptr cuando no tiene la intención de mantener múltiples referencias al mismo objeto. Por ejemplo, utilícelo como un puntero a la memoria que se asigna al ingresar algún ámbito y se desasigna al salir del alcance.
    • Utilizar std::shared_ptr cuando quiera referirse a su objeto desde múltiples lugares, y no quiere que se desasigne hasta que todas estas referencias hayan desaparecido.
    • Utilizar std::weak_ptr cuando desee referirse a su objeto desde múltiples lugares, para aquellas referencias que está bien ignorar y desasignar (de modo que simplemente notarán que el objeto se ha ido cuando intenta desreferencia).
    • No use el boost:: punteros inteligentes o std::auto_ptr excepto en casos especiales en los que puede leer si es necesario.
  • ¡Oye, no pregunté cuál usar! 
    Ah, pero realmente querías, admítelo.
  • Entonces, ¿cuándo debería usar punteros regulares? 
    Principalmente en código que es ajeno a la propiedad de la memoria. Esto normalmente sería en funciones que obtienen un puntero desde otro lugar y no asignan, desasignan ni almacenan una copia del puntero que dura más que su ejecución.

170
2018-05-09 19:06



Puntero inteligente es un tipo de puntero con alguna funcionalidad adicional, p. desasignación automática de memoria, recuento 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 de puntero inteligente simple es std::auto_ptr (capítulo 20.4.5 del estándar C ++), que permite desasignar la memoria automáticamente cuando está fuera del alcance y que es más sólida que el uso del puntero simple cuando se lanzan excepciones, aunque es menos flexible.

Otro tipo conveniente es boost::shared_ptr que implementa el recuento de referencias y desasigna automáticamente la memoria cuando no quedan referencias al objeto. Esto ayuda a evitar fugas de memoria y es fácil de usar para implementar RAII.

El tema está cubierto en profundidad en el libro "Plantillas C ++: la guía completa" por David Vandevoorde, Nicolai M. Josuttis, capítulo Capítulo 20. Punteros inteligentes. Algunos temas cubiertos:


96
2017-09-20 00:32



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 el ->y * operadores. Lo que significa que su objeto se ve semánticamente como un puntero, pero puede hacerlo de una forma más fría, como el recuento 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.


33
2017-09-20 01:53



Un puntero inteligente es como un puntero normal (mecanografiado), como "char *", excepto cuando el puntero sale del alcance y luego se borra también lo que apunta. Puede usarlo como lo haría con un puntero normal, usando "->", pero no si necesita un puntero real a los datos. Para eso, puedes usar "& * ptr".

Es útil para:

  • Objetos que se deben asignar con nuevos, pero que le gustaría tener la misma duración que algo en esa pila. Si el objeto está asignado a un puntero inteligente, se eliminarán cuando el programa salga de esa función / bloque.

  • Los miembros de datos de las clases, de modo que cuando se elimina el objeto, todos los datos de propiedad también se eliminan, sin ningún código especial en el destructor (deberá asegurarse de que el destructor sea virtual, lo cual es casi siempre una buena acción) .

Puedes no quiero usar un puntero inteligente cuando:

  • ... el puntero no debería ser el propietario de los datos ... es decir, cuando solo está utilizando los datos, pero quiere que sobrevivan a la función en la que lo está haciendo referencia.
  • ... el puntero inteligente no va a ser destruido en algún momento. No desea que se guarde en la memoria que nunca se destruya (como en un objeto que se asigna dinámicamente pero no se eliminará explícitamente).
  • ... dos punteros inteligentes podrían apuntar a los mismos datos. (Sin embargo, hay punteros más inteligentes que manejarán eso ... eso se llama recuento de referencia.)

Ver también:


26
2017-09-20 00:13



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

Los punteros inteligentes más comúnmente utilizados son std::tr1::shared_ptr (o boost::shared_ptr), y, con menos frecuencia, 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 que los objetos deben "pasar a través de los límites de DLL" (el caso de pesadilla común si es diferente) libcs se utilizan entre su código y las DLL).


14
2017-09-20 00:14



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

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

Por ejemplo, Aumentar proporciona las siguientes implementaciones de puntero inteligente:

  • shared_ptr<T> es un puntero a T usando un conteo de referencia para determinar cuándo el objeto ya no es necesario.
  • scoped_ptr<T> es un puntero borrado automáticamente cuando sale 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 el tipo T para proporcionar su propio mecanismo de conteo de referencia.
  • 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 descripción lineal de cada una y se pueden usar según las necesidades, para obtener más detalles y ejemplos, puede consultar la documentación de Boost.

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


14
2018-03-12 09:51



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 a los operadores de puntero estándar. Tienen una serie de ventajas sobre los punteros regulares. Están garantizados para ser inicializados como punteros nulos o punteros a un objeto de montón. Se verifica la dirección a través de un puntero nulo. No eliminar nunca es necesario. Los objetos se liberan automáticamente cuando el último puntero a ellos se ha ido. Un problema importante con estos indicadores inteligentes es que, a diferencia de los indicadores habituales, no respetan la herencia. Los punteros inteligentes no son atractivos para el código polimórfico. A continuación se incluye 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í es cómo usarlo:

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

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

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

9
2018-03-07 09:03



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

En informática, un puntero inteligente   es un tipo de datos abstractos que   simula un puntero mientras proporciona   características adicionales, como automático   recolección de basura o comprobación de límites.   Estas características adicionales están destinadas   para reducir los errores causados ​​por el mal uso de   punteros al tiempo que conserva la eficiencia.   Los punteros inteligentes suelen hacer un seguimiento de   los objetos que los señalan para el   propósito de la gestión de la memoria. los   el uso indebido de punteros es una fuente importante   de errores: la asignación constante,   desasignación y referencia que debe   ser realizado por un programa escrito   usar punteros lo hace muy probable   que se producirán algunas pérdidas de memoria.   Los punteros inteligentes intentan evitar la memoria   gotea al hacer el recurso   desasignación automática: cuando el   puntero a un objeto (o el último en   serie de punteros) se destruye, por   ejemplo porque sale del alcance,   el objeto puntiagudo también se destruye.


8
2017-09-20 00:12