I’m a newbie at C++ (coming from C). I understand conceptually how RAII should work, but I have trouble fitting a simple socket connection handler into it.
Current code:
void accept_ev(event_handler::token &t, int listenfd)
{
int newfd = accept(listenfd, NULL, NULL);
if (newfd < 0)
throw api_server_accept_failed(*this, errno);
connections.insert(api_server_connection(newfd));
}
This is obviously not safe, since api_server_connection constructor might raise an exception before assigning the fd to its member variable.
So my next thought was to move the accept into the constructor. The problem is I really want api_server_connection to be agnostic about where the fd came from. E.g. if I want to support inetd in the future it might just as well be passed into the program as fd 0.
So how do I do this. Should I use different constructors for each way to obtain an fd? Should I perhaps make subclasses? Another option could be to have a lambda function?
Or should I just catch any error and close the fd in the caller in that case?
Ignoring, sockets for the moment, what you usually want to do is divide things into two phases.
In the first phase, you do things that may throw, but if they do, you can restore the system to a sane state (preferably a state as if nothing happened at all).
In the second phase, you do things that you may not be able to undo, but that you know for sure will never throw.
To do that, you need some assurance about what can/will throw and (particularly) some assurances about at least a few rather specific operations that can never throw at all (e.g., swapping two items).
To facilitate this, you normally want to do that restoration to a sane state in the dtor, so if an exception is thrown, the destructor will clean up automatically.
Unfortunately, it’s difficult to say a lot more than that about your specific code/situation, because we simply don’t know enough about the classes you’re using.