If you allocate data for your errors dynamically (perhaps they have formatted strings for informative messages), you'll want to return a pointer, otherwise you'll have copies throughoutNot sure what you mean exactly but I don't think you need copies all over the place since this is C++ so instances can be moved and there's also copy elision. And should you use 'int fun(Error& error)' with error containing an std::string for the message then at least the principle of 'you need a pointer' is dealt with by std::string insetad of having to do it manually.
There is a solid rationale behind it.
Might be but from a usage point of view it seems harder to deal with than alternatives (see 'ErrorOr' in another comment, or passing 'Error& error' or so: these days raw pointers are frowned upon, imo with reason, and raw pointer to pointer doesn't make that any better). Suppose I write an
int fun(struct Error **error) {
if(somethingWentWrong) {
StoreErrorCode(error);
}
}
In StoreErrorCode I'd first have to check if '* error == nullptr' or not. If not I'd have to '* error = new Error()', I guess. If '* error' does point to an instance, what do I do? 'delete(* error)' followed by new? Or reuse the current instance? That's imo too many questions already and I didn't even store an error code yet. Sure the answers to those questions can be dealt with in an error handling API used by the library. Or one could rely on some convention that '* error' always is NULL and hope everyone follows that convention. But unless somehowe proven that this is really really needed for performance reasons I'd pick any easier to work with (and hence less likely to introduce bugs) C++-style alternative over pointer to pointer anytime.