In an ideal world, you can use them to do what you ask. By "ideal world" I mean one where you have your choice of MPI implementation and are able to administer it yourself (instead of convincing the cluster owner to reconfigure it for you). The minimal configuration for exceptions will include the: --with-exceptions flag, and possibly a few more.
I've used LAM most often, and by default exceptions are disabled. I believe this is the default for other implementations as well.
They work in the same vein as 'vanilla' C++ exceptions. And they do work inside parallel executed code.
At some point in your startup code, you want to enable them:
MPI::COMM_WORLD.Set_errhandler ( MPI::ERRORS_THROW_EXCEPTIONS );
(if your library isn't configured to allow exceptions, this is probably a bad idea -- behaviour "undefined" according to LAM)
And then:
try { /* something that can fail */ }
catch ( MPI::Exception e ) {
cout << "Oops: " << e.Get_error_string() << e.Get_error_code();
MPI::COMM_WORLD.Abort (-1) ;
}
As for it being good or bad practice, I can't really say. I haven't seen extensive use of them in code written by hardened MPI hackers, but that may be because the code is generally more C than C++ in my experience.
A middle ground between error codes and exceptions may be error handlers, in a nutshell you can assign functions that will be called when a particular error (designated by code) occurs. This might be an option if you can't get your administrator on board with enabling exceptions.