¿Cuándo usarías un std :: auto_ptr en lugar de boost :: shared_ptr?
-
22-07-2019 - |
Pregunta
Nos hemos movido a usar boost :: shared_ptr
en todo nuestro código, sin embargo, todavía tenemos algunos casos aislados en los que usamos std :: auto_ptr
, incluidas las clases de singleton:
template < typename TYPE >
class SharedSingleton
{
public:
static TYPE& Instance()
{
if (_ptrInstance.get() == NULL)
_ptrInstance.reset(new TYPE);
return *_ptrInstance;
}
protected:
SharedSingleton() {};
private:
static std::auto_ptr < TYPE > _ptrInstance;
};
Me han dicho que hay una muy buena razón por la cual esto no se ha convertido en shared_ptr
, pero por mi vida no puedo entender por qué. Sé que auto_ptr
eventualmente se marcará como depreciado en el siguiente estándar, por lo que me gustaría saber qué / cómo puedo reemplazar esta implementación .
Además, ¿hay alguna otra razón por la que consideraría usar un auto_ptr
en lugar de un shared_ptr
? ¿Ve algún problema? ¿te mudas a shared_ptr en el futuro?
Editar:
- Entonces, en respuesta a " ¿puedo reemplazar con seguridad
auto_ptr
conshared_ptr
en el código anterior " ;, la respuesta es sí, sin embargo, tomaré un pequeño golpe de rendimiento . - Cuando
auto_ptr
finalmente se marca como depreciado y pasamos astd :: shared_ptr
, necesitaremos probar a fondo nuestro código para asegurarnos de que estamos cumpliendo por la semántica de propiedad diferente.
Solución
auto_ptr
y shared_ptr
resuelven problemas completamente diferentes. Uno no reemplaza al otro.
auto_ptr
es un envoltorio delgado alrededor de punteros para implementar RAII semántica , para que los recursos siempre se liberen, incluso cuando se enfrentan a excepciones. auto_ptr
no realiza ningún recuento de referencias o similar, no hace que múltiples punteros apunten al mismo objeto al crear copias. De hecho, es muy diferente. auto_ptr
es una de las pocas clases en las que el operador de asignación modifica el objeto fuente . Considere este complemento descarado de la página de wikipedia auto_ptr :
int *i = new int;
auto_ptr<int> x(i);
auto_ptr<int> y;
y = x;
cout << x.get() << endl; // Print NULL
cout << y.get() << endl; // Print non-NULL address i
Tenga en cuenta cómo ejecutar
y = x;
modifica no solo y sino también x.
La plantilla boost :: shared_ptr
facilita el manejo de múltiples punteros al mismo objeto, y el objeto solo se elimina después de que la última referencia a él se salga del alcance. Esta característica no es útil en su escenario, que (intenta) implementar un Singleton . En su escenario, siempre hay 0 referencias a 1 referencia al único objeto de la clase, si existe.
En esencia, los objetos auto_ptr
y los objetos shared_ptr
tienen una semántica completamente diferente (es por eso que no puede usar el primero en contenedores, pero hacerlo con el último está bien), y espero que tengas buenas pruebas para detectar cualquier regresión que hayas introducido al portar tu código. : -}
Otros consejos
Otros han respondido por qué este código usa un auto_ptr
en lugar de un shared_ptr
. Para abordar sus otras preguntas:
¿Qué / cómo puedo reemplazar esta implementación?
Utilice boost :: scoped_ptr
o unique_ptr
(disponible tanto en Boost como en el nuevo estándar C ++). Tanto scoped_ptr
como unique_ptr
proporcionan una propiedad estricta (y ninguna sobrecarga de conteo de referencias), y evitan la sorprendente semántica de eliminación en copia de auto_ptr
.
Además, ¿hay alguna otra razón por la que consideraría usar un auto_ptr
en lugar de un shared_ptr
? ¿Y ve algún problema para pasar a shared_ptr
en el futuro?
Personalmente, no usaría un auto_ptr
. Delete-on-copy es demasiado poco intuitivo. Herb Sutter parece estar de acuerdo . Cambiar a scoped_ptr
, unique_ptr
o shared_ptr
no debería ofrecer problemas. Específicamente, shared_ptr
debería ser un reemplazo directo si no le importa la sobrecarga de conteo de referencias. scoped_ptr
es un reemplazo directo si no está utilizando las capacidades de transferencia de propiedad de auto_ptr
. Si está utilizando la transferencia de propiedad, entonces unique_ptr
es casi un reemplazo directo, excepto que necesita llamar explícitamente a move
para transferir la propiedad. Consulte aquí para ver un ejemplo.
auto_ptr es el único tipo de puntero inteligente que uso. Lo uso porque no uso Boost, y porque generalmente prefiero que mis clases orientadas a aplicaciones / negocios explícitamente definir la semántica y el orden de eliminación, en lugar de depender de colecciones de punteros inteligentes o individuales.