valores valor tipos retorno programacion parametros funciones funcion devolución con c++

c++ - tipos - ¿Cuál debería ser el tipo de retorno cuando la función podría no tener un valor para devolver?



tipos de funciones en c (6)

En los viejos tiempos, podría tener una función como esta:

const char* find_response(const char* const id) const;

Si no se puede encontrar el elemento, entonces se puede devolver un nulo para indicar el hecho, de lo contrario, obviamente devuelva la cadena relevante.

Pero cuando la función se cambia a:

const std::string& find_response(const std::string& id) const;

¿Qué devuelves para indicar el ítem no encontrado?

O la firma debería ser:

bool find_response(const std::string& id, std::string& value) const;

¿Cuál sería la forma más elegante y moderna de C ++?


¿Cuál sería la forma más elegante y moderna de C ++?

Hay, como siempre, no solo una solución a este problema.

Si decide optar por cualquier solución que haga referencia a la instancia de respuesta original, se encuentra en un camino resbaladizo cuando se trata de la administración de aliasing y memoria, especialmente en un entorno de múltiples subprocesos. Al copiar la respuesta a la persona que llama, no surgen tales problemas.

Hoy, haría esto:

std::unique_ptr<std::string> find_response(const std::string& id) const;

De esa manera, puede verificar nullptr como "en los viejos tiempos" y es 100% claro quién es responsable de aclarar la instancia devuelta: la persona que llama.

El único inconveniente que veo de esto, es la copia adicional de la cadena de respuesta, pero no lo descarte como un inconveniente hasta que sea medido y demostrado.

Otra forma es hacer lo que se hace al buscar std::set<> y std::map<> - devolver un std::pair<bool, const char*> donde un valor es bool is_found y el otro es const char* response De esa manera, no se obtiene la "sobrecarga" de la copia de respuesta adicional, solo del std::pair<> devuelto que es probable que el compilador optimice al máximo.


Creo que la segunda forma es mejor. O puedes escribir así:

int find_response(const std::string& id, std::string& value) const;

Si esta función devuelve -1, le dice que no encuentra la respuesta.


El uso de punteros en C ++ se perdona si necesita devolver una entidad que pueda contener nulos. Esto es ampliamente aceptado. Pero, por supuesto, bool find_response(const std::string& id, std::string& value) const; Es bastante detallado. Así que es cuestión de tu elección.


Hay varias buenas soluciones aquí ya. Pero en aras de la exhaustividad me gustaría añadir este. Si no desea confiar en boost::optional , puede implementar fácilmente su propia clase como

class SearchResult { SearchResult(std::string stringFound, bool isValid = true) : m_stringFound(stringFound), m_isResultValid(isValid) { } const std::string &getString() const { return m_stringFound; } bool isValid() const { return m_isResultValid; } private: std::string m_stringFound; bool m_isResultValid; };

Obviamente, su firma de método se ve así entonces

const SearchResult& find_response(const std::string& id) const;

Pero básicamente eso es lo mismo que la solución de impulso.


Si la función devuelve una cadena por referencia, pero necesita la capacidad de indicar que no existe tal cadena, la solución más obvia es devolver un puntero, que es básicamente una referencia que puede ser nula, es decir, exactamente lo que se buscó.

const std::string* find_response(const std::string& id) const;


boost::optional . Fue diseñado específicamente para este tipo de situación.

Tenga en cuenta que se incluirá en el próximo estándar de C ++ 14 como std::optional . Actualización: Después de revisar los comentarios del organismo nacional a N3690, std::optional se eliminó del documento de trabajo C ++ 14 a una Especificación Técnica por separado. No es parte del borrador de C ++ 14 a partir de n3797.

Comparado con std::unique_ptr , evita la asignación de memoria dinámica y expresa más claramente su propósito. Sin embargo, std::unique_ptr es mejor para el polimorfismo (por ejemplo, métodos de fábrica) y para almacenar valores en contenedores.

Ejemplo de uso:

#include <string> #include <boost/none.hpp> #include <boost/optional.hpp> class A { private: std::string value; public: A(std::string s) : value(s) {} boost::optional<std::string> find_response(const std::string& id) const { if(id == value) return std::string("Found it!"); else return boost::none; //or //return boost::make_optional(id == value, std::string("Found it!")); } //You can use boost::optional with references, //but I''m unfamiliar with possible applications of this. boost::optional<const std::string&> get_id() const { return value; } }; #include <iostream> int main() { A a("42"); boost::optional<std::string> response = a.find_response("42"); //auto is handy if(response) { std::cout << *response; } }