Hay muchos punteros en C ++, pero para ser honesto en 5 años más o menos en la programación de C ++ (específicamente con Qt Framework), solo uso el viejo puntero sin formato:
SomeKindOfObject *someKindOfObject = new SomeKindOfObject();
Sé que hay muchos otros punteros "inteligentes":
// shared pointer:
shared_ptr<SomeKindofObject> Object;
// unique pointer:
unique_ptr<SomeKindofObject> Object;
// weak pointer:
weak_ptr<SomeKindofObject> Object;
Pero no tengo la menor idea de qué hacer con ellos y qué pueden ofrecerme en comparación con los punteros en bruto.
Por ejemplo, tengo este encabezado de clase:
#ifndef LIBRARY
#define LIBRARY
class LIBRARY
{
public:
    // Permanent list that will be updated from time to time where
    // each items can be modified everywhere in the code:
    QList<ItemThatWillBeUsedEveryWhere*> listOfUselessThings; 
private:
    // Temporary reader that will read something to put in the list
    // and be quickly deleted:
    QSettings *_reader;
    // A dialog that will show something (just for the sake of example):
    QDialog *_dialog;
};
#endif 
Esto claramente no es exhaustivo, pero para cada uno de estos 3 punteros, ¿está bien dejarlos "en bruto" o debería usar algo más apropiado?
Y en la segunda vez, si un empleador leerá el código, ¿será estricto con el tipo de punteros que uso o no?
                    
                        c++
                                programming-practices
                                pointers
                                qt
                                smart-pointer
                                
                    
                    
                        CheshireChild
fuente
                
                fuente

Respuestas:
Un puntero "en bruto" no está administrado. Es decir, la siguiente línea:
... perderá memoria si
deleteno se ejecuta un acompañamiento en el momento adecuado.auto_ptrCon el fin de minimizar estos casos,
std::auto_ptr<>se introdujo. Sin embargo, debido a las limitaciones de C ++ anteriores al estándar de 2011, aún es muy fácilauto_ptrperder memoria. Sin embargo, es suficiente para casos limitados como este:Uno de sus casos de uso más débiles es en contenedores. Esto se debe a que si se realiza una copia de un
auto_ptr<>y la copia anterior no se restablece cuidadosamente, el contenedor puede eliminar el puntero y perder datos.unique_ptrComo reemplazo, C ++ 11 introdujo
std::unique_ptr<>:Tal
unique_ptr<>se limpiará correctamente, incluso cuando se pasa entre funciones. Lo hace representando semánticamente la "propiedad" del puntero: el "propietario" lo limpia. Esto lo hace ideal para usar en contenedores:A diferencia
auto_ptr<>,unique_ptr<>se comporta bien aquí, y cuando sevectorcambia el tamaño, ninguno de los objetos se eliminará accidentalmente mientras lasvectorcopias se almacenan.shared_ptryweak_ptrunique_ptr<>es útil, sin duda, pero hay casos en los que desea que dos partes de su base de código puedan hacer referencia al mismo objeto y copiar el puntero, sin dejar de garantizar la limpieza adecuada. Por ejemplo, un árbol podría verse así, cuando se usastd::shared_ptr<>:En este caso, incluso podemos conservar múltiples copias de un nodo raíz, y el árbol se limpiará correctamente cuando se destruyan todas las copias del nodo raíz.
Esto funciona porque cada uno
shared_ptr<>mantiene no solo el puntero al objeto, sino también un recuento de referencia de todos losshared_ptr<>objetos que hacen referencia al mismo puntero. Cuando se crea uno nuevo, el recuento aumenta. Cuando uno es destruido, la cuenta baja. Cuando el recuento llega a cero, el puntero esdeleted.Esto presenta un problema: las estructuras de doble enlace terminan con referencias circulares. Digamos que queremos agregar un
parentpuntero a nuestro árbolNode:Ahora, si eliminamos a
Node, hay una referencia cíclica a él. Nunca serádeleted porque su recuento de referencia nunca será cero.Para resolver este problema, utiliza un
std::weak_ptr<>:Ahora, las cosas funcionarán correctamente y eliminar un nodo no dejará referencias atascadas en el nodo principal. Sin embargo, hacer que caminar por el árbol sea un poco más complicado:
De esta manera, puede bloquear una referencia al nodo, y tiene una garantía razonable de que no desaparecerá mientras está trabajando en él, ya que está aferrándose a uno
shared_ptr<>de ellos.make_sharedymake_uniqueAhora, hay algunos problemas menores con
shared_ptr<>yunique_ptr<>que deben abordarse. Las siguientes dos líneas tienen un problema:Si
thrower()arroja una excepción, ambas líneas perderán memoria. Y más que eso,shared_ptr<>mantiene el recuento de referencia lejos del objeto al que apunta y esto puede significar una segunda asignación). Eso no suele ser deseable.C ++ 11 proporciona
std::make_shared<>()y C ++ 14 proporcionastd::make_unique<>()para resolver este problema:Ahora, en ambos casos, incluso si
thrower()arroja una excepción, no habrá una pérdida de memoria. Como beneficio adicional,make_shared<>()tiene la oportunidad de crear su recuento de referencia en el mismo espacio de memoria que su objeto administrado, lo que puede ser más rápido y ahorrar algunos bytes de memoria, ¡al tiempo que le ofrece una garantía de seguridad excepcional!Notas sobre Qt
Sin embargo, debe tenerse en cuenta que Qt, que debe ser compatible con compiladores anteriores a C ++ 11, tiene su propio modelo de recolección de basura: muchos
QObjecttienen un mecanismo en el que serán destruidos adecuadamente sin la necesidad del usuariodelete.No sé cómo
QObjectse comportarán los mensajes de correo electrónico administrados por C ++ 11, por lo que no puedo decir queshared_ptr<QDialog>sea una buena idea. No tengo suficiente experiencia con Qt para decirlo con certeza, pero creo que Qt5 se ha ajustado para este caso de uso.fuente
shared_ptres un objeto separado, una asignación separada, delnewobjeto ed. Existen en diferentes lugares.make_sharedtiene la capacidad de juntarlos en la misma ubicación, lo que mejora la localidad de caché, entre otras cosas.shared_ptrEs un objeto. Y para administrar un objeto, debe asignar un objeto (recuentos de referencia (débil + fuerte) + destructor).make_sharedpermite asignar eso y el objeto administrado como una sola pieza.unique_ptrno los usa, por lo que no hay una ventaja correspondiente, aparte de asegurarse de que el objeto siempre sea propiedad del puntero inteligente. Por otro lado, uno puede tener unshared_ptrque posee un objeto subyacente y representa unnullptr, o que no posee y representa un puntero no nulo.shared_ptrhace: 1. Comparte la propiedad de algún objeto (representado por un objeto interno asignado dinámicamente que tiene un recuento de referencias débil y fuerte, así como un eliminador) . 2. Contiene un puntero. Esas dos partes son independientes.make_uniqueymake_sharedambos se aseguran de que el objeto asignado se coloque de forma segura en un puntero inteligente. Además,make_sharedpermite asignar el objeto de propiedad y el puntero administrado juntos.