> ...leave the error for something else...
In my experience, the amount of interesting logic that "something else" does is vanishingly small. An arbitrary real-world example probably just logs or returns a string that is opaque and mostly useless to any potential error recovery mechanism.
In theory one could throw a FileExistsException with semantic and accessible data like filePath, but as things get this specific, they practically become part of the API. And a leaky part at that. The top-level entities that need to handle the exception need to know, somehow, that (1) encapsulated implementation details may throw something specific and (2) what to do with the thrown events.
So, practically, programs tend to catch std::exception, and pass the opaque error string on to some form of external I/O system (logs) with some minimally informative error status code (ERROR, 5XX, -1, false, null).
It is interesting to perform transaction failure operations, but there is no std::transaction_aborted, std::connection_dropped, or std::resource_busy. More realistically, std::exception is caught, which could just as easily be std::bad_alloc or std::domain_error. What do you do with a domain_error? I don't know either.
At any rate, the most interesting feature for transactional logic is RAII semantics, and you don't need to use exceptions to leverage those.