c++ boost c++11 unique-ptr boost-optional

c++ - ¿Cuándo usar boost:: opcional y cuándo usar std:: unique_ptr en los casos en los que desea implementar una función que pueda devolver "nada"?



c++11 unique-ptr (7)

Entonces, ¿hay alguna razón para preferir uno sobre el otro?

Expresan una intención muy diferente: optional dice que la función no puede dar un resultado para darle (y eso no es un caso de error). unique_ptr le dice algo acerca de la semántica de propiedad (y es más aceptable de usar con null, para expresar un error).

Usualmente usaría el que exprese mejor la intención detrás de la interfaz.

Por ejemplo, considere que estaba escribiendo un servidor HTTP, que intenta analizar un búfer recibido en un objeto de solicitud HTTP. Cuando intenta analizar un búfer incompleto, no hay ningún caso de error, simplemente tiene que esperar y almacenar más datos, e intente nuevamente.

Expresaría esto usando optional , para dejar claro que la función puede no devolver nada (y no devolver nada no es un caso de error).

En caso de que mi análisis tuviera que validar cosas (por ejemplo, un analizador de expresiones regulares debería producir un error si la expresión analizada no es válida) devolvería un unique_ptr nulo, o mejor aún, lanzar una excepción.

Por lo que entiendo, hay 2 * formas en que puede implementar una función que a veces no devuelve un resultado (por ejemplo, una persona que se encuentra en una lista de personas).

*: ignoramos la versión ptr sin formato, emparejamos con un indicador bool, y la excepción cuando no encontramos ninguna versión.

boost::optional<Person> findPersonInList();

o

std::unique_ptr<Person> findPersonInList();

Entonces, ¿hay alguna razón para preferir uno sobre el otro?


Ah, ¿Xeo no apareció todavía?

Bueno, esto te lo dije una vez y lo repetiré: estos dos son objetos completamente diferentes con propósitos diferentes.

  • unique_ptr significa que tengo un objeto . Es solo una forma diferente de decir "Soy un objeto". Por lo tanto, null unique_ptr es algo que puede llamar la atención. Esperaba un objeto, pero no conseguí nada; ¡El código debe estar equivocado!
  • optional significa que a veces no se puede inicializar, pero está bien . En este caso, no hay preocupaciones; si no es None , es el comportamiento que se ha pensado.

El hecho de que ambos se conviertan implícitamente en bool no significa que se puedan usar de manera intercambiable. Use optional con el código que probablemente no genere ningún resultado (por ejemplo, leer un flujo). Utilice unique_ptr en objetos de fábrica; lo más probable es que creen un objeto para usted, y si no, lanzan una excepción.

Una conclusión con respecto a su ejemplo: find debe devolver optional .


Conceptualmente se reduce a esto, dado el requisito de ser nullable:

std::optional tiene valor semántico, pila de almacenamiento.

std::unique_ptr tiene semántica de movimiento, tienda de almacenamiento dinámico.

Si desea una semántica de valor y una tienda de almacenamiento dinámico, use std::indirect http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0201r1.pdf .

(Si desea mover la semántica y la pila de tiendas ... No lo sé. ¿Supongo que es un unique_ptr con un asignador de pila?)


Depende: ¿desea devolver un identificador o una copia ?

Si desea devolver un identificador :

  • Person*
  • boost::optional<Person&>

Son dos opciones aceptables. Tiendo a usar una clase Ptr<Person> que se lanza en caso de acceso nulo, pero esa es mi paranoia.

Si desea devolver una copia :

  • boost::optional<Person> para clases no polimórficas
  • std::unique_ptr<Person> para clases polimórficas

Debido a que la asignación dinámica incurre en una sobrecarga, por lo que solo se usa cuando es necesario.


Hay una cuarta forma de hacerlo: hacer que la función lance una excepción si no se encuentra nada.

Sé que esto realmente no responde a tu pregunta y, por lo tanto, me disculpo, pero quizás no lo hayas pensado.


La respuesta general es que sus intenciones se expresan con boost::optional y no con std::unique_ptr . Dicho esto, su caso especial de una operación de find probablemente debería ajustarse a la forma estándar de hacerlo de la biblioteca, asumiendo que su tipo subyacente tiene un concepto de iteradores: devuelva un iterador a end() si no se encuentra ningún elemento, y un iterador a el elemento de lo contrario.


boost::optional declara más claramente tu intención. std::unique_ptr documentar explícitamente que std::unique_ptr vacío significa que no hay valor para devolver