On 28/05/2019 02:28, JeanHeyd Meneide wrote:
Regarding destructors: yes. In the standard library, we have implicit noexcept on destructors. This inherits that same noexcept guarantee and is how it is implemented both here and (soon) in the Standard, pending LWG approval. unique_ptr has a noexcept .reset(); shared_ptr does not (control block allocation may fail, etc.). However, other RAII types that wrap objects and call non-noexcept functions are marked noexcept themselves: e.g., lock_guard which calls mutex.unlock https://en.cppreference.com/w/cpp/thread/mutex/unlock.
lock_guard is a "true" RAII type, though, and mutex unlock is an "destruction type" operation that should never actually fail even if the method was not explicitly marked noexcept. (Especially when interacting with legacy mutex types that might not indicate noexcept behaviour.) out_ptr is *not* an RAII type and its destructor has "non-destructive" side effects that are known to invoke memory allocation and construction, which are both exception-prone operations. I think it makes the most sense to declare it noexcept(false). Or possibly conditional noexcept on all the operations performed, so that as you say above, it would be noexcept for unique_ptr and not for shared_ptr. It's probably also worth adding to the caveats that the smart pointer must always be declared before and outside of the full-expression that contains the out_ptr. (While you'd normally expect this in order to achieve useful variable lifetime scoping, it would probably be possible to construct an example that does this incorrectly.) If they're in the same expression then it might be possible for the compiler to destroy the smart pointer before destroying the out_ptr, and then hilarity will ensue. Regarding the "poorly designed C APIs" caveat: some APIs guarantee that they do not alter the value of output parameters on failure. So you definitely should not assume that the value is always set to nullptr on failure; at least for out_ptr you should be passing in a raw pointer that is already nullptr, not uninitialised or some other value. If you're not doing that, the bug is in your library, not in the API. (Your caveat is correct for inout_ptr, however.)