2010-06-01 12 views
52

¿Hay alguna clase equivalente para C++ 1x std :: unique_ptr en las bibliotecas de impulso? El comportamiento que estoy buscando es ser capaz de tener una función de fábrica excepción de fallos, al igual que ...unique_ptr boost equivalent?

std::unique_ptr<Base> create_base() 
{ 
    return std::unique_ptr<Base>(new Derived); 
} 

void some_other_function() 
{ 
    std::unique_ptr<Base> b = create_base(); 

    // Do some stuff with b that may or may not throw an exception... 

    // Now b is destructed automagically. 
} 

EDIT: En este momento, estoy usando este truco, que parece que lo mejor que pueda llegar a este punto ...

Base* create_base() 
{ 
    return new Derived; 
} 

void some_other_function() 
{ 
    boost::scoped_ptr<Base> b = create_base(); 

    // Do some stuff with b that may or may not throw an exception... 

    // Now b is deleted automagically. 
} 
+0

Además, ¿se puede crear este efecto haciendo que el constructor de copia tenga semántica de movimiento, y luego el destructor comprueba antes de liberar? –

Respuesta

64

No es posible crear algo como unique_ptr sin C++ 0x (donde forma parte de la biblioteca estándar, por lo que Boost no necesita proporcionarlo).

Específicamente sin referencias rvalue, que son una característica en C++ 0x, una implementación robusta de unique_ptr es imposible, con o sin Boost.

En C++ 03, hay algunas alternativas posibles, aunque cada uno tiene sus defectos.

  • boost::shared_ptr es probablemente el reemplazo más simple en términos de capabilidades. Puede usarlo de manera segura en cualquier lugar donde de otra manera usaría un unique_ptr y funcionaría. Simplemente no sería tan eficiente, debido al recuento de referencias agregado. Pero si está buscando un reemplazo simple que pueda manejar todo lo que unique_ptr puede hacer, esta es probablemente su mejor opción. (Por supuesto, un shared_ptr puede hacer mucho más también, pero puede también ser utilizado simplemente como una gota en el reemplazo para unique_ptr.)
  • boost::scoped_ptr es similar a unique_ptr pero no permite la transferencia de la propiedad. Funciona muy bien siempre que el puntero inteligente esté destinado a conservar la propiedad exclusiva a lo largo de su vida útil.
  • std::auto_ptr funciona muy similar a unique_ptr, pero tiene algunas limitaciones, principalmente que no se puede almacenar en contenedores de biblioteca estándar. Si simplemente está buscando un puntero que permita la transferencia de propiedad, pero que no está destinado a ser almacenado en contenedores o copiado, probablemente sea una buena apuesta.
+4

+1 para 'auto_ptr' - ya que' unique_ptr' no se compilará en [lugares donde auto_ptr causa errores] (http://stackoverflow.com/questions/111478/why-is-it-wrong-to-use-stdauto -ptr-with-stl-containers), esto es exactamente lo que OP está buscando. –

+4

El unique_ptr de Howard Hinnant para C++ 03 funciona bastante bien teniendo en cuenta que las referencias r-value no existen. –

+0

Esto no es completamente cierto, ya que Howard Hinnant ha demostrado que usa la emulación de semántica de movimiento que ya se ha revisado en Boost. Espero que alguien lleve a cabo su implementación e incluirlo en Boost pronto. –

5

¿Qué tal unique_ptr de la biblioteca interprocess?

+0

¿Se puede devolver de una función de forma segura? No pude encontrar nada al respecto (pero tal vez estoy solo ciego). Además, ¿es lo "correcto" para usar, dado que está en la biblioteca entre procesos en lugar de en la biblioteca de punteros inteligentes? –

+0

@wowus: No. Eso se basa en la semántica de movimientos que son nuevos en C++ 0x. Eso no puede ser simplemente emulado por boost - esa característica debe existir en el compilador mismo. –

+0

Acabo de mirar, necesita referencias de valor r. Por lo tanto, no es lo que estoy buscando. –

10

Es posible que desee para tratar de 'prueba de concepto' unique_ptr<> aplicación de Howard Hinnant para C++ 03 (descargo de responsabilidad - Yo no tengo):

Uno de sus ejemplos devuelve un unique_ptr<int>:

unique_ptr<int> factory(int i) 
{ 
    return unique_ptr<int>(new int(i)); 
} 
+0

Lo he usado en código de producción, funciona bastante bien. El único problema que teníamos era llamar a 'boost :: make_shared', para una' clase' con un parámetro 'unique_ptr'. –

4

he usado Howard Hinnant de unique_ptr. Si no eres realmente bueno para leer los errores de metaprogramación de tu compilador, es posible que quieras mantenerte alejado. Sin embargo, actúa como un único píxel en el 90% de los casos.

De lo contrario, sugiero pasar los parámetros como boost::scoped_ptr& y cambiar internamente para robar la propiedad. Para obtener valores de retorno de estilo unique_ptr use auto_ptr. Capture el valor de retorno auto_ptr en shared_ptr o scoped_ptr para evitar el uso directo del auto_ptr.

33

A partir de Boost 1.57 hay una implementación oficial de unique_ptr en la biblioteca Boost.Move.

Desde el documentation:

(...) una gota en el reemplazo para std :: unique_ptr, utilizable también de C++ 03 compiladores.

El código está disponible en el archivo de encabezado <boost/move/unique_ptr.hpp> y vive en el espacio de nombre boost::movelib. Además, la biblioteca Boost.Move proporciona la función de fábrica make_unique() en <boost/move/make_unique.hpp>, también en el espacio de nombres boost::movelib.

De ahí el ejemplo de la pregunta podría ser implementado de esta manera:

#include <boost/move/unique_ptr.hpp> 

using boost::movelib::unique_ptr; 

unique_ptr<Base> create_base() 
{ 
    return unique_ptr<Base>(new Derived); 
} 

Ver a live example on Wandbox. Tenga en cuenta que el código compila bien con gcc 4.6.4 en el modo C++ 98 (!).

Lo que es interesante en boost::movelib::unique_ptr cuando se aplica a su caso con clases base/derivadas, la implementación proporciona una verificación en tiempo de compilación para la declaración de un destructor virtual en la clase base. Si omite el the code won't compile (haga clic en el botón "Ejecutar (...)" para ver el mensaje de error del compilador).

Un problema menor es que incluye venir del directorio boost/move pero el código vive en el espacio de nombres boost::movelib (diferencia sutil, pero puede ser molesto).

Vea también a thread on boost mailing list para más detalles.

Gracias a Ion Gaztañaga por esta pieza de código absolutamente única y útil.