Aquí está el capítulo (gratuito) de Alexandrescu sobre la esencia de la creación de punteros inteligentes de diferentes sabores: informit.com/articles/article.aspx?p=31529 En su implementación, usa argumentos de plantilla como "políticas" para especificar qué atributos quiere ( por ejemplo, conteo de referencias), mientras que la biblioteca estándar usa clases separadas. Tenga en cuenta que también estaba escribiendo antes de que las referencias de rvalue estuvieran disponibles para hacer posible algo como std :: unique_ptr.
metal
Me gustaría agregar un punto más a la pregunta anterior, el puntero inteligente std :: shared_ptr no tiene un operador de subíndice y no admite la aritmética de ponter, podemos usar get () para obtener un puntero integrado.
suresh m
Respuestas:
1884
ACTUALIZAR
Esta respuesta es bastante antigua, por lo que describe lo que era "bueno" en ese momento, que eran los punteros inteligentes proporcionados por la biblioteca Boost. Puesto que C ++ 11, la biblioteca estándar ha proporcionado suficientes tipos punteros inteligentes, y por lo que debería favorecer el uso de std::unique_ptr, std::shared_ptry std::weak_ptr.
También había std::auto_ptr . Era muy parecido a un puntero de alcance, excepto que también tenía la habilidad peligrosa "especial" de ser copiada, lo que también transfiere la propiedad inesperadamente. Estaba en desuso en C ++ 11 y se eliminó en C ++ 17 , por lo que no debe usarlo.
std::auto_ptr<MyObject> p1 (newMyObject());
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.
ANTIGUA RESPUESTA
Un puntero inteligente es una clase que envuelve un puntero C ++ 'crudo' (o 'desnudo'), para administrar la vida útil del objeto al que se apunta. No existe un único tipo de puntero inteligente, pero todos intentan abstraer un puntero sin formato de manera práctica.
Se deben preferir los punteros inteligentes a los punteros en bruto. Si siente que necesita usar punteros (primero considere si realmente lo hace), normalmente querrá usar un puntero inteligente ya que esto puede aliviar muchos de los problemas con punteros sin procesar, principalmente olvidando eliminar el objeto y la pérdida de memoria.
Con 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 goalMyObject* ptr =newMyObject();
ptr->DoSomething();// Use the object in some waydelete 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. Todavía tiene que crear el objeto, pero ya no tiene que preocuparse por destruirlo.
SomeSmartPtr<MyObject> ptr(newMyObject());
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 contenedor de puntero inteligente, como el implementado por boost::scoped_ptrostd::unique_ptr .
void f(){{
std::unique_ptr<MyObject> ptr(newMyObject());
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.}
Tenga en cuenta que las std::unique_ptrinstancias no se pueden copiar. Esto evita que el puntero se elimine varias veces (incorrectamente). Sin embargo, puede pasar referencias a otras funciones que llame.
std::unique_ptrs son útiles cuando desea vincular la vida útil del objeto a un bloque de código en particular, o si lo incrusta como datos de miembros dentro de otro objeto, la vida útil de ese otro objeto. El objeto existe hasta que se sale del bloque de código que lo contiene, o hasta que el objeto que lo contiene se destruye.
Una política de puntero inteligente más compleja implica el recuento de referencias del puntero. Esto permite copiar el puntero. Cuando se destruye la última "referencia" al objeto, se elimina el objeto. Esta política es implementada por boost::shared_ptry std::shared_ptr.
void f(){typedef std::shared_ptr<MyObject>MyObjectPtr;// nice short aliasMyObjectPtr p1;// Empty{MyObjectPtr p2(newMyObject());// 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 ni a otro objeto.
Hay un inconveniente para hacer referencia a punteros contados: la posibilidad de crear una referencia colgante:
// Create the smart pointer on the heapMyObjectPtr* pp =newMyObjectPtr(newMyObject())// Hmm, we forgot to destroy the smart pointer,// because of that, the object is never destroyed!
Otra posibilidad es crear referencias circulares:
structOwner{
std::shared_ptr<Owner> other;};
std::shared_ptr<Owner> p1 (newOwner());
std::shared_ptr<Owner> p2 (newOwner());
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 a weak_ptrpara definir una referencia débil (sin contar) a a shared_ptr.
¿Quieres decir en std::auto_ptr<MyObject> p1 (new MyObject());lugar de std::auto_ptr<MyObject> p1 (new Owner());?
Mateen Ulhaq
35
Impresionante respuesta. Sería bueno si se actualizara para c ++ 11. Encontré esta respuesta buscando información sobre el nuevo estándar 11 y sería bueno si los futuros visitantes pudieran encontrar la información actualizada. Sé que auto_ptr ha quedado en desuso. Creo que shated_ptr y weak_ptr existen como se describe, y creo que scoped_ptr ahora es unique_ptr en el estándar. Si esto es cierto, ¿se puede actualizar esta respuesta por favor?
SaulBack
16
Decir que la posibilidad de crear una referencia colgante es una desventaja de los punteros contados de referencia es absolutamente una locura. Las posibles referencias colgantes son un inconveniente de cualquier puntero C ++ . De hecho, es exactamente ese inconveniente lo que los punteros inteligentes están destinados a aliviar .
Michael Dorst
16
Si declara un puntero a un puntero inteligente (como se hizo en el ejemplo), renuncia a sabiendas a todos los beneficios del puntero inteligente. Esto no es un inconveniente o una falla de diseño, es el uso más idiota imaginable.
Michael Dorst
3
A const std::auto_ptres seguro de usar, si está atascado con C ++ 03. Lo usé bastante para el patrón Pimpl hasta que obtuve acceso a C ++ 11.
Toby Speight
303
Aquí hay una respuesta simple para estos días de C ++ moderno (C ++ 11 y posterior):
¿Qué es un puntero inteligente?
Es un tipo cuyos valores se pueden usar como punteros, pero que proporciona la característica adicional de administración automática de memoria: cuando un puntero inteligente ya no está en uso, la memoria a la que apunta se desasigna (consulte también la definición más detallada en Wikipedia ).
¿Cuándo debo usar uno?
En el código que implica rastrear la propiedad de una pieza de 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?
Úselo std::unique_ptrcuando no tenga la intención de mantener múltiples referencias al mismo objeto. Por ejemplo, úselo para un puntero a la memoria que se asigna al ingresar algún alcance y se desasigna al salir del alcance.
Úselo std::shared_ptrcuando desee referirse a su objeto desde múltiples lugares, y no desee que su objeto sea desasignado hasta que todas estas referencias hayan desaparecido.
Úselo std::weak_ptrcuando quiera referirse a su objeto desde múltiples lugares, para aquellas referencias para las cuales está bien ignorar y desasignar (para que solo noten que el objeto se ha ido cuando intenta desreferenciar).
No utilice los boost::punteros inteligentes o std::auto_ptrexcepto en casos especiales en los que pueda leer si es necesario.
¡Hey, no pregunté cuál usar!
Ah, pero realmente querías admitirlo.
Entonces, ¿cuándo debo 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 de otro lugar y no asignan ni desasignan, y no almacenan una copia del puntero que dura más que su ejecución.
Vale la pena señalar que, si bien los punteros inteligentes (propietarios) ayudan con la gestión adecuada de la memoria, los punteros brutos (no propietarios) siguen siendo útiles para otros fines organizativos en las estructuras de datos. Herb Sutter hizo una gran presentación sobre este asunto en CppCon 2016, que puedes ver en YouTube: Leak-Freedom en C ++ ... Por defecto.
wiktor.wandachowicz
1
@ wiktor.wandachowicz T*es std::unique_ptr<T>lo que std::weak_ptr<T>esstd::shared_ptr<T>
Caleth
@Caleth: No, no diría eso.
einpoklum
1
@TonyTannous: Con respeto: fue una edición importante; y no siento que mi respuesta, que es abstracta, la necesite. Le sugiero que haga del ejemplo una respuesta separada, en el enlace a este en un comentario.
Einpoklum
112
El puntero inteligente es un tipo de puntero con alguna funcionalidad adicional, por ejemplo, desasignación automática de memoria, recuento de referencias, etc.
Uno de los tipos simples de puntero inteligente es std::auto_ptr(capítulo 20.4.5 del estándar C ++), que permite desasignar memoria automáticamente cuando está fuera de alcance y que es más robusto que el uso simple de puntero cuando se lanzan excepciones, aunque menos flexible.
Otro tipo conveniente es el boost::shared_ptrque implementa el recuento de referencias y desasigna automáticamente la memoria cuando no quedan referencias al objeto. Esto ayuda a evitar pérdidas de memoria y es fácil de usar para implementar RAII .
La advertencia std::auto_ptres obsoleta y altamente desalentadora, ya que puede transferir accidentalmente la propiedad. - C ++ 11 elimina la necesidad de Boost, uso: std::unique_ptr, std::shared_ptrystd::weak_ptr
ninMonkey
42
Las definiciones proporcionadas por Chris, Sergdev y Llyod son correctas. Sin embargo, prefiero una definición más simple, solo para simplificar mi vida: un puntero inteligente es simplemente una clase que sobrecarga los operadores -> y *. Lo que significa que su objeto se parece semánticamente a un puntero, pero puede hacerlo hacer cosas mucho más geniales, incluido el recuento de referencias, la destrucción automática, etc.
shared_ptry auto_ptrson suficientes en la mayoría de los casos, pero vienen con su propio conjunto de pequeñas idiosincrasias.
Un puntero inteligente es como un puntero normal (mecanografiado), como "char *", excepto cuando el puntero se sale del alcance y lo que señala también se elimina. Puede usarlo como lo haría con un puntero normal, usando "->", pero no si necesita un puntero real a los datos. Para eso, puede usar "& * ptr".
Es útil para:
Objetos que deben asignarse con nuevos, pero que le gustaría tener la misma vida útil que algo en esa pila. Si el objeto se asigna a un puntero inteligente, se eliminarán cuando el programa salga de esa función / bloque.
Miembros de las clases de datos, de modo que cuando se elimina el objeto, también se eliminan todos los datos de propiedad, sin ningún código especial en el destructor (deberá asegurarse de que el destructor sea virtual, lo que casi siempre es algo bueno) .
Es posible que no desee utilizar un puntero inteligente cuando:
... el puntero no debería poseer los datos ... es decir, cuando solo está utilizando los datos, pero desea que sobreviva a la función a la que hace referencia.
... el puntero inteligente no se va a destruir en algún momento. No desea que se quede en la memoria que nunca se destruye (como en un objeto que se asigna dinámicamente pero que no se eliminará explícitamente).
... dos punteros inteligentes pueden apuntar a los mismos datos. (Sin embargo, hay punteros aún más inteligentes que manejarán eso ... eso se llama conteo de referencias ).
La mayoría de los tipos de punteros inteligentes manejan la disposición del objeto 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 utilizadas son std::tr1::shared_ptr(o boost::shared_ptr), y, con menor frecuencia, std::auto_ptr. Recomiendo el uso regular de shared_ptr.
shared_ptres 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 la DLL" (el caso común de pesadilla si libcse utilizan diferentes s entre su código y las DLL).
Un puntero inteligente es un objeto que actúa como un puntero, pero que además proporciona control sobre la construcción, destrucción, copia, movimiento y desreferenciación.
Uno puede implementar su propio puntero inteligente, pero muchas bibliotecas también proporcionan implementaciones de puntero inteligente, cada una con diferentes ventajas y desventajas.
Por ejemplo, Boost proporciona las siguientes implementaciones de puntero inteligente:
shared_ptr<T>es un puntero para Tutilizar 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 sale del alcance. Ninguna asignación es posible.
intrusive_ptr<T>es otro puntero de recuento de referencia. Proporciona un mejor rendimiento que shared_ptr, pero requiere que el tipo Tproporcione su propio mecanismo de conteo de referencia.
weak_ptr<T>es un puntero débil, que trabaja en conjunto shared_ptrpara 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_ptrpara propiedad única, std::shared_ptrpara propiedad compartida y std::weak_ptr. std::auto_ptrexistía en C ++ 03 pero ahora está en desuso.
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 plantillas 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 inicializarán como punteros nulos o punteros a un objeto de montón. Se verifica la indirección a través de un puntero nulo. No es necesario borrar nunca. Los objetos se liberan automáticamente cuando el último puntero hacia ellos se ha ido. 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:
En ciencias de la computación, un puntero inteligente es un tipo de datos abstracto que simula un puntero mientras proporciona características 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 mientras se mantiene la eficiencia. Los punteros inteligentes generalmente 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 ocurran algunas pérdidas de memoria. Los punteros inteligentes intentan evitar pérdidas de memoria al hacer que la desasignación de recursos sea automática: cuando se destruye el puntero a un objeto (o el último de una serie de punteros),
Deje que T sea una clase en este tutorial Los punteros en C ++ se pueden dividir en 3 tipos:
1) Punteros crudos :
T a;
T * _ptr =&a;
Mantienen una dirección de memoria en una ubicación en la memoria. Úselo con precaución, ya que los programas se vuelven complejos y difíciles de seguir.
Punteros con dirección o datos constantes {Leer al revés}
T a ;const T * ptr1 =&a ;
T const* ptr1 =&a ;
Puntero a un tipo de datos T que es una constante. Lo que significa que no puede cambiar el tipo de datos con el puntero. es decir *ptr1 = 19; no trabajará. Pero puedes mover el puntero. es decir ptr1++ , ptr1--; etc funcionará Leer al revés: puntero para escribir T, que es constante
T *const ptr2 ;
Un puntero constante a un tipo de datos T. Lo que significa que no puede mover el puntero, pero puede cambiar el valor señalado por el puntero. es decir *ptr2 = 19, funcionará pero ptr2++ ; ptr2--etc. no funcionará. Leer al revés: puntero constante a un tipo T
const T *const ptr3 ;
Un puntero constante a un tipo de datos constante T. Lo que significa que no puede mover el puntero ni cambiar el puntero del tipo de datos para que sea el puntero. es decir. ptr3-- ; ptr3++ ; *ptr3 = 19;no trabajará
3) Punteros inteligentes : { #include <memory>}
Puntero compartido :
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
Implementado utilizando el recuento de referencias para realizar un seguimiento de cuántas "cosas" apuntan al objeto señalado por el puntero. Cuando este recuento llega a 0, el objeto se elimina automáticamente, es decir, se elimina el objeto cuando todo el share_ptr que apunta al objeto queda fuera de alcance. Esto elimina el dolor de cabeza de tener que eliminar objetos que ha asignado usando new.
Puntero débil:
ayuda a lidiar con la referencia cíclica que surge cuando se usa el puntero compartido. se eliminará cuando los punteros compartidos estén fuera de alcance. Para resolver esto, cambie el miembro interno de shared_ptr a weak_ptr. Nota: Para acceder al elemento señalado por un puntero débil, use lock (), esto devuelve un débil_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 scopeif(!wk.expired()) wk.lock()->memFn();// Check if shared ptr has gone out of scope before access
Puntero único:
puntero inteligente liviano con propiedad exclusiva. Se usa cuando el puntero apunta a objetos únicos sin compartir los objetos entre los punteros.
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
Para cambiar el objeto señalado por el ptr único, use la semántica de movimiento
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
Referencias: Pueden considerarse esencialmente como punteros constantes, es decir, un puntero que es constante y no se puede mover con una mejor sintaxis.
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
Un puntero inteligente es una clase, un contenedor de un puntero normal. A diferencia de los punteros normales, el círculo de vida del punto inteligente se basa en un recuento de referencia (cuántas veces se asigna el objeto puntero inteligente). Entonces, cada vez que se asigna un puntero inteligente a otro, el recuento de referencia interna más más. Y cada vez que el objeto se sale del alcance, la referencia cuenta menos menos.
El puntero automático, aunque parece similar, es totalmente diferente del puntero inteligente. Es una clase conveniente que desasigna el recurso cada vez que un objeto puntero automático sale del alcance variable. Hasta cierto punto, hace que un puntero (a la memoria asignada dinámicamente) funcione de manera similar a una variable de pila (asignada estáticamente en tiempo de compilación).
Los punteros inteligentes son aquellos en los que no tiene que preocuparse por la desasignación de memoria, el intercambio de recursos y la transferencia.
Puede usar estos punteros 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.
Las respuestas existentes son buenas, pero no cubren qué hacer cuando un puntero inteligente no es la respuesta (completa) al problema que está tratando de resolver.
Entre otras cosas (explicado bien en otras respuestas), usar un puntero inteligente es una posible solución para ¿Cómo usamos una clase abstracta como un tipo de retorno de función? que ha sido marcado como un duplicado de esta pregunta. Sin embargo, la primera pregunta que debe hacerse si está tentado a especificar una clase base abstracta (o de hecho, cualquiera) como tipo de retorno en C ++ es "¿qué quiere decir realmente?". Hay una buena discusión (con más referencias) de la programación idiomática orientada a objetos en C ++ (y cómo esto es diferente a otros lenguajes) en la documentación de la biblioteca de contenedor de puntero de impulso. En resumen, en C ++ tienes que pensar en la propiedad. Con qué punteros inteligentes le ayudan, pero no son la única solución, o siempre son una solución completa (no le dan una copia polimórfica) y no siempre son una solución que desea exponer en su interfaz (y un retorno de función suena horrible mucho como una interfaz). Puede ser suficiente devolver una referencia, por ejemplo. Pero en todos estos casos (puntero inteligente, contenedor de puntero o simplemente devolver una referencia) ha cambiado el retorno de un valor a alguna forma de referencia . Si realmente necesita una copia, es posible que deba agregar más "modismos" repetitivos o ir más allá de la OOP idiomática (o de otro modo) en C ++ a un polimorfismo más genérico utilizando bibliotecas como Adobe Poly o Boost..
Respuestas:
ACTUALIZAR
Esta respuesta es bastante antigua, por lo que describe lo que era "bueno" en ese momento, que eran los punteros inteligentes proporcionados por la biblioteca Boost. Puesto que C ++ 11, la biblioteca estándar ha proporcionado suficientes tipos punteros inteligentes, y por lo que debería favorecer el uso de
std::unique_ptr
,std::shared_ptr
ystd::weak_ptr
.También había
std::auto_ptr
. Era muy parecido a un puntero de alcance, excepto que también tenía la habilidad peligrosa "especial" de ser copiada, lo que también transfiere la propiedad inesperadamente.Estaba en desuso en C ++ 11 y se eliminó en C ++ 17 , por lo que no debe usarlo.
ANTIGUA RESPUESTA
Un puntero inteligente es una clase que envuelve un puntero C ++ 'crudo' (o 'desnudo'), para administrar la vida útil del objeto al que se apunta. No existe un único tipo de puntero inteligente, pero todos intentan abstraer un puntero sin formato de manera práctica.
Se deben preferir los punteros inteligentes a los punteros en bruto. Si siente que necesita usar punteros (primero considere si realmente lo hace), normalmente querrá usar un puntero inteligente ya que esto puede aliviar muchos de los problemas con punteros sin procesar, principalmente olvidando eliminar el objeto y la pérdida de memoria.
Con punteros en bruto, el programador tiene que destruir explícitamente el objeto cuando ya no es útil.
Un puntero inteligente, en comparación, define una política sobre cuándo se destruye el objeto. Todavía tiene que crear el objeto, pero ya no tiene que preocuparse por destruirlo.
La política más simple en uso implica el alcance del objeto contenedor de puntero inteligente, como el implementado por
boost::scoped_ptr
ostd::unique_ptr
.Tenga en cuenta que las
std::unique_ptr
instancias no se pueden copiar. Esto evita que el puntero se elimine varias veces (incorrectamente). Sin embargo, puede pasar referencias a otras funciones que llame.std::unique_ptr
s son útiles cuando desea vincular la vida útil del objeto a un bloque de código en particular, o si lo incrusta como datos de miembros dentro de otro objeto, la vida útil de ese otro objeto. El objeto existe hasta que se sale del bloque de código que lo contiene, o hasta que el objeto que lo contiene se destruye.Una política de puntero inteligente más compleja implica el recuento de referencias del puntero. Esto permite copiar el puntero. Cuando se destruye la última "referencia" al objeto, se elimina el objeto. Esta política es implementada por
boost::shared_ptr
ystd::shared_ptr
.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 ni a otro objeto.
Hay un inconveniente para hacer referencia a punteros contados: la posibilidad de crear una referencia colgante:
Otra posibilidad es crear referencias circulares:
Para evitar este problema, tanto Boost como C ++ 11 han definido a
weak_ptr
para definir una referencia débil (sin contar) a ashared_ptr
.fuente
std::auto_ptr<MyObject> p1 (new MyObject());
lugar destd::auto_ptr<MyObject> p1 (new Owner());
?const std::auto_ptr
es seguro de usar, si está atascado con C ++ 03. Lo usé bastante para el patrón Pimpl hasta que obtuve acceso a C ++ 11.Aquí hay una respuesta simple para estos días de C ++ moderno (C ++ 11 y posterior):
Es un tipo cuyos valores se pueden usar como punteros, pero que proporciona la característica adicional de administración automática de memoria: cuando un puntero inteligente ya no está en uso, la memoria a la que apunta se desasigna (consulte también la definición más detallada en Wikipedia ).
En el código que implica rastrear la propiedad de una pieza de memoria, asignar o desasignar; el puntero inteligente a menudo le ahorra la necesidad de hacer estas cosas explícitamente.
std::unique_ptr
cuando no tenga la intención de mantener múltiples referencias al mismo objeto. Por ejemplo, úselo para un puntero a la memoria que se asigna al ingresar algún alcance y se desasigna al salir del alcance.std::shared_ptr
cuando desee referirse a su objeto desde múltiples lugares, y no desee que su objeto sea desasignado hasta que todas estas referencias hayan desaparecido.std::weak_ptr
cuando quiera referirse a su objeto desde múltiples lugares, para aquellas referencias para las cuales está bien ignorar y desasignar (para que solo noten que el objeto se ha ido cuando intenta desreferenciar).boost::
punteros inteligentes ostd::auto_ptr
excepto en casos especiales en los que pueda leer si es necesario.Ah, pero realmente querías admitirlo.
Principalmente en código que es ajeno a la propiedad de la memoria. Esto normalmente sería en funciones que obtienen un puntero de otro lugar y no asignan ni desasignan, y no almacenan una copia del puntero que dura más que su ejecución.
fuente
T*
esstd::unique_ptr<T>
lo questd::weak_ptr<T>
esstd::shared_ptr<T>
El puntero inteligente es un tipo de puntero con alguna funcionalidad adicional, por ejemplo, desasignación automática de memoria, recuento de referencias, etc.
Hay una pequeña introducción disponible en la página Punteros inteligentes: ¿qué, por qué y 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 memoria automáticamente cuando está fuera de alcance y que es más robusto que el uso simple de puntero cuando se lanzan excepciones, aunque menos flexible.Otro tipo conveniente es el
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 pérdidas de memoria y es fácil de usar para implementar RAII .El tema se trata en profundidad en el libro "Plantillas C ++: La guía completa" de David Vandevoorde, Nicolai M. Josuttis , capítulo Capítulo 20. Punteros inteligentes. Algunos temas cubiertos:
fuente
std::auto_ptr
es obsoleta y altamente desalentadora, ya que puede transferir accidentalmente la propiedad. - C ++ 11 elimina la necesidad de Boost, uso:std::unique_ptr
,std::shared_ptr
ystd::weak_ptr
Las definiciones proporcionadas por Chris, Sergdev y Llyod son correctas. Sin embargo, prefiero una definición más simple, solo para simplificar mi vida: un puntero inteligente es simplemente una clase que sobrecarga los operadores
->
y*
. Lo que significa que su objeto se parece semánticamente a un puntero, pero puede hacerlo hacer cosas mucho más geniales, incluido el recuento de referencias, la destrucción automática, etc.shared_ptr
yauto_ptr
son suficientes en la mayoría de los casos, pero vienen con su propio conjunto de pequeñas idiosincrasias.fuente
Un puntero inteligente es como un puntero normal (mecanografiado), como "char *", excepto cuando el puntero se sale del alcance y lo que señala también se elimina. Puede usarlo como lo haría con un puntero normal, usando "->", pero no si necesita un puntero real a los datos. Para eso, puede usar "& * ptr".
Es útil para:
Objetos que deben asignarse con nuevos, pero que le gustaría tener la misma vida útil que algo en esa pila. Si el objeto se asigna a un puntero inteligente, se eliminarán cuando el programa salga de esa función / bloque.
Miembros de las clases de datos, de modo que cuando se elimina el objeto, también se eliminan todos los datos de propiedad, sin ningún código especial en el destructor (deberá asegurarse de que el destructor sea virtual, lo que casi siempre es algo bueno) .
Es posible que no desee utilizar un puntero inteligente cuando:
Ver también:
fuente
La mayoría de los tipos de punteros inteligentes manejan la disposición del objeto 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 utilizadas son
std::tr1::shared_ptr
(oboost::shared_ptr
), y, con menor frecuencia,std::auto_ptr
. Recomiendo el uso regular deshared_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 la DLL" (el caso común de pesadilla silibc
se utilizan diferentes s entre su código y las DLL).fuente
Un puntero inteligente es un objeto que actúa como un puntero, pero que además proporciona control sobre la construcción, destrucción, copia, movimiento y desreferenciación.
Uno puede implementar su propio puntero inteligente, pero muchas bibliotecas también proporcionan implementaciones de puntero inteligente, cada una con diferentes ventajas y desventajas.
Por ejemplo, Boost proporciona las siguientes implementaciones de puntero inteligente:
shared_ptr<T>
es un puntero paraT
utilizar 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 sale del alcance. Ninguna asignación es posible.intrusive_ptr<T>
es otro puntero de recuento de referencia. Proporciona un mejor rendimiento queshared_ptr
, pero requiere que el tipoT
proporcione su propio mecanismo de conteo de referencia.weak_ptr<T>
es un puntero débil, que trabaja en conjuntoshared_ptr
para evitar referencias circulares.shared_array<T>
es comoshared_ptr
, pero para matrices deT
.scoped_array<T>
es comoscoped_ptr
, pero para matrices deT
.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 propiedad única,std::shared_ptr
para propiedad compartida ystd::weak_ptr
.std::auto_ptr
existía en C ++ 03 pero ahora está en desuso.fuente
scoped_ptr
no es como una declaración localconst unique_ptr
, que también se elimina al salir del ámbito.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 plantillas 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 inicializarán como punteros nulos o punteros a un objeto de montón. Se verifica la indirección a través de un puntero nulo. No es necesario borrar nunca. Los objetos se liberan automáticamente cuando el último puntero hacia ellos se ha ido. 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:
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:
Al igual que otros operadores sobrecargados, p se comportará como un puntero normal,
fuente
http://en.wikipedia.org/wiki/Smart_pointer
fuente
Deje que T sea una clase en este tutorial Los punteros en C ++ se pueden dividir en 3 tipos:
1) Punteros crudos :
Mantienen una dirección de memoria en una ubicación en la memoria. Úselo con precaución, ya que los programas se vuelven complejos y difíciles de seguir.
Punteros con dirección o datos constantes {Leer al revés}
Puntero a un tipo de datos T que es una constante. Lo que significa que no puede cambiar el tipo de datos con el puntero. es decir
*ptr1 = 19
; no trabajará. Pero puedes mover el puntero. es decirptr1++ , ptr1--
; etc funcionará Leer al revés: puntero para escribir T, que es constanteUn puntero constante a un tipo de datos T. Lo que significa que no puede mover el puntero, pero puede cambiar el valor señalado por el puntero. es decir
*ptr2 = 19
, funcionará peroptr2++ ; ptr2--
etc. no funcionará. Leer al revés: puntero constante a un tipo TUn puntero constante a un tipo de datos constante T. Lo que significa que no puede mover el puntero ni cambiar el puntero del tipo de datos para que sea el puntero. es decir.
ptr3-- ; ptr3++ ; *ptr3 = 19;
no trabajará3) Punteros inteligentes : {
#include <memory>
}Puntero compartido :
Implementado utilizando el recuento de referencias para realizar un seguimiento de cuántas "cosas" apuntan al objeto señalado por el puntero. Cuando este recuento llega a 0, el objeto se elimina automáticamente, es decir, se elimina el objeto cuando todo el share_ptr que apunta al objeto queda fuera de alcance. Esto elimina el dolor de cabeza de tener que eliminar objetos que ha asignado usando new.
Puntero débil: ayuda a lidiar con la referencia cíclica que surge cuando se usa el puntero compartido. se eliminará cuando los punteros compartidos estén fuera de alcance. Para resolver esto, cambie el miembro interno de shared_ptr a weak_ptr. Nota: Para acceder al elemento señalado por un puntero débil, use lock (), esto devuelve un débil_ptr.
Ver: ¿ Cuándo es útil std :: weak_ptr?
Puntero único: puntero inteligente liviano con propiedad exclusiva. Se usa cuando el puntero apunta a objetos únicos sin compartir los objetos entre los punteros.
Para cambiar el objeto señalado por el ptr único, use la semántica de movimiento
Referencias: Pueden considerarse esencialmente como punteros constantes, es decir, un puntero que es constante y no se puede mover con una mejor sintaxis.
Ver: ¿Cuáles son las diferencias entre una variable de puntero y una variable de referencia en C ++?
Referencia: https://www.youtube.com/channel/UCEOGtxYTB6vo6MQ-WQ9W_nQ Gracias a Andre por señalar esta pregunta.
fuente
Un puntero inteligente es una clase, un contenedor de un puntero normal. A diferencia de los punteros normales, el círculo de vida del punto inteligente se basa en un recuento de referencia (cuántas veces se asigna el objeto puntero inteligente). Entonces, cada vez que se asigna un puntero inteligente a otro, el recuento de referencia interna más más. Y cada vez que el objeto se sale del alcance, la referencia cuenta menos menos.
El puntero automático, aunque parece similar, es totalmente diferente del puntero inteligente. Es una clase conveniente que desasigna el recurso cada vez que un objeto puntero automático sale del alcance variable. Hasta cierto punto, hace que un puntero (a la memoria asignada dinámicamente) funcione de manera similar a una variable de pila (asignada estáticamente en tiempo de compilación).
fuente
Los punteros inteligentes son aquellos en los que no tiene que preocuparse por la desasignación de memoria, el intercambio de recursos y la transferencia.
Puede usar estos punteros 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.
fuente
Las respuestas existentes son buenas, pero no cubren qué hacer cuando un puntero inteligente no es la respuesta (completa) al problema que está tratando de resolver.
Entre otras cosas (explicado bien en otras respuestas), usar un puntero inteligente es una posible solución para ¿Cómo usamos una clase abstracta como un tipo de retorno de función? que ha sido marcado como un duplicado de esta pregunta. Sin embargo, la primera pregunta que debe hacerse si está tentado a especificar una clase base abstracta (o de hecho, cualquiera) como tipo de retorno en C ++ es "¿qué quiere decir realmente?". Hay una buena discusión (con más referencias) de la programación idiomática orientada a objetos en C ++ (y cómo esto es diferente a otros lenguajes) en la documentación de la biblioteca de contenedor de puntero de impulso. En resumen, en C ++ tienes que pensar en la propiedad. Con qué punteros inteligentes le ayudan, pero no son la única solución, o siempre son una solución completa (no le dan una copia polimórfica) y no siempre son una solución que desea exponer en su interfaz (y un retorno de función suena horrible mucho como una interfaz). Puede ser suficiente devolver una referencia, por ejemplo. Pero en todos estos casos (puntero inteligente, contenedor de puntero o simplemente devolver una referencia) ha cambiado el retorno de un valor a alguna forma de referencia . Si realmente necesita una copia, es posible que deba agregar más "modismos" repetitivos o ir más allá de la OOP idiomática (o de otro modo) en C ++ a un polimorfismo más genérico utilizando bibliotecas como Adobe Poly o Boost..
fuente