2009-03-10 10 views
9

Tengo un proyecto que me gustaría hacer un mayor uso de punteros inteligentes. En general, he tenido éxito en este objetivo. Sin embargo, me he encontrado con algunas cosas que no estoy seguro de cuál es la "mejor práctica".devolviendo un 'puntero' que se requiere para ser sostenido por un puntero inteligente

Básicamente me gustaría devolver un "puntero" de una función, pero requiere que el usuario lo mantenga en un puntero inteligente. No solo eso, no quiero ordenar un puntero inteligente en particular (compartido versus ámbito).

El problema es principalmente que no parece haber una forma adecuada de actualizar un scoped_ptr a un shared_ptr (esa sería la solución ideal, creo). Entiendo por qué no hicieron esto, ya que permitiría la transferencia de propiedad, lo que puede dar lugar a algunos problemas como los que tiene std::auto_ptr.

Sin embargo, la transferencia de propiedad parece una buena idea para esta caja. Así que mi idea es la siguiente:

// contrived example of factory pattern 
std::auto_ptr<A> func() { return std::auto_ptr<A>(new A); } 

esto funciona "ok" ya que ambos scoped_ptr y shared_ptr tienen constructores que tienen la propiedad de un std::auto_ptr.

Así que mi pregunta es, ¿es esta una buena práctica? ¿Hay una mejor solución? La única alternativa real que hemos sido capaces de llegar a es el uso de una plantilla de plantilla como el valor de retorno de esta manera:

// similar to above example 
template <template <typename> class P> 
P<A> func() { return P<A>(new A); } 

que en realidad podría funcionar bien, excepto que creo que sería necesario algún trabajo para conseguir que se trabaje con un scoped_ptr también.

¿Pensamientos?

Respuesta

11

Usando std::auto_ptres la buenas prácticas, de hecho such example fue sugerido por Bjarne Stroustrup.

La semántica de movimiento de auto_ptr le da las herramientas adecuadas para manejarlo.

Por ejemplo:

auto_ptr<Foo> make_foo() 
{ 
    return auto_ptr<Foo>(new Foo); 
} 

Foo *raw_pointer=make_foo().release(); 
shared_ptr<Foo> shared_pointer=make_foo(); 
auto_ptr<Foo> auto_pointer=make_foo(); 

Si regresa shared_ptr no se puede puntero vuelve a los normales, con auto_ptr que pueda. Siempre puede actualizar auto_ptr para compartir pero no en otra dirección.

Otro punto importante, shared_ptr utiliza el recuento de referencias atómicas, que es mucho más lento que el trabajo simple pero totalmente eficiente que hace auto_ptr.

P.S .: scoped_ptr es sólo la versión de auto_ptr para Poors --- Que no es copiable y no no tiene Constuctor defecto. Es más como la versión "menos confusa" de auto_ptr, en comparación con shared_ptr no está en tr1. En general, no hay mucho ventajas de utilizar scoped_ptr sobre auto_ptr

+0

shared_ptr en la compilación de subprocesos individuales no utiliza recuento de referencias atómicas. –

+0

Tiene razón, pero por defecto boost es construir en versión multihilo. – Artyom

+2

La ventaja de utilizar scoped_ptr sobre auto_ptr es cuando desea dejar en claro que no debe copiar el puntero. Simplemente no puedes con scoped_ptr. Se trata de transmitir sus intenciones, al igual que su ejemplo lo hace con auto_ptr y transferencia de propiedad. –

3

Si construye una fábrica, está bien que simplemente devuelva un puntero. Y el usuario de su fábrica puede tomar su propia decisión sobre cómo y dónde colocar este puntero.
Si necesita imponer el uso del puntero inteligente, debe restringir las opciones ya que no quiere que utilicen las "incorrectas".
So boost :: shared_ptr. Pero es mejor tipearlo luego en MyClassPtr o MyClass :: ptr.
Aún así, las fábricas son como "nuevas". Cuando quiero pongo el resultado de nuevo dentro de std :: auto_ptr. Pero no quiero ser forzado a llamar "liberar" todas las veces cuando no quiero el puntero inteligente.

+0

cierto, pero me gustaría hacer cumplir el uso de un puntero inteligente si es posible. –

+0

Estoy de acuerdo, todos somos adultos aquí. Regrese un puntero desnudo y deje que el usuario del código decida cómo captar mejor el valor de retorno. Creo que el constructor de shared_ptr de un auto_ptr se va a desaparecer (auto_ptr va a estar en desuso). –

+0

cuando auto_ptr está privado en C++ 0x, unique_ptr lo reemplazará. Cambiaría a regresar a unique_ptr entonces. – Aaron

1

con C++ 11 debe ser capaz de utilizar std::unique_ptr como los otros tipos de punteros inteligentes tienen constructores que toman un std::unique_ptr. Si mantiene una lista interna de dichos recursos, probablemente desee utilizar std::shared_ptr.

Cuestiones relacionadas