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:

  1. Entonces, en respuesta a " ¿puedo reemplazar con seguridad auto_ptr con shared_ptr en el código anterior " ;, la respuesta es sí, sin embargo, tomaré un pequeño golpe de rendimiento .
  2. Cuando auto_ptr finalmente se marca como depreciado y pasamos a std :: shared_ptr , necesitaremos probar a fondo nuestro código para asegurarnos de que estamos cumpliendo por la semántica de propiedad diferente.
¿Fue útil?

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top