1. return an error code
2. if the caller consider the issue to require an exception, they will do it themselves
You can also have entrypoints to the library that will throw exceptions, and other versions that won't, and let the caller decide what they want to use.
Though of course that's more work.
Regarding the point of performances, that makes me think of https://news.ycombinator.com/item?id=22483028, discussing "Low-cost Deterministic C++ Exceptions for Embedded Systems". It would definitely be very interesting to see what is now possible if exceptions are cheaper.