This is a pretty perfect exception handling scenario (at least as it was intended). Exception handling is usually suitable for handling external input errors, since in this case the external input comes from the socket.
You already have a try / catch block, but I would suggest eliminating it, since there is no recovery code. Keep try / catch blocks mostly in areas where you are committing a change transaction. Capturing the exception, discards the changes, returns the system to an acceptable state, and possibly displays some kind of message.
Something like that:
void Session::cBeginSession() { if (ssh_options_set(mySession, SSH_OPTIONS_HOST, &hostIP) != 0) throw runtime_error("Unable to set Host address"); if (ssh_options_set(mySession, SSH_OPTIONS_LOG_VERBOSITY, SSH_LOG_PROTOCOL) != 0) throw runtime_error("Protocol option log verbosity unable to set."); if (ssh_options_set(mySession, SSH_OPTIONS_PORT, &port) != 0) throw runtime_error("Unable to set port"); std::cout << "Session started\n"; }
Let the client code that calls this function catch an exception on the node where it is suitable for handling and recovering from an error. Just talk about how to throw an exception in case of these external input errors.
Note that exception handling is generally extremely cheap in non-exceptional cases (where you don't drop) with optimizations such as zero cost EH. However, these optimizers for handling exception handlers make the rare case a lot slower when you actually throw an exception. Therefore, exceptions should be used for really exceptional cases caused by some kind of external input that your software usually cannot handle, as in this case.
Another caveat related to certain types of larger systems (e.g. plugin architecture) is that usually exceptions should not overlap module boundaries.
This is a somewhat opinionated opinion, but I do not recommend having many catch branches based on the type of exception (as is usually the case in Java, for example). Often there is no need to distinguish between the actual type of exception, as relaying the message to the user, for example. Choose exceptions as normal / rough as possible, and keep try/catch blocks to a minimum (high-level transaction-oriented mentality: transactions succeed in general or fail and roll back in general).
Otherwise, exceptions can really simplify such cases, and the entire C ++ library (and even parts of the language) usually raises exceptions (I really believe that C ++ and exception handling are inextricably linked), so this can be useful for using them. since a reliable program, as a rule, should generally catch them.