std::try_cast 与 (const&&)=删除

  • P2927 Proposal: Proposes a facility exception_ptr_cast with signature template<class T> const T* exception_ptr_cast(const exception_ptr&) noexcept;.

    • Example usage in modifying Nicolas Guillemot's 2013 example: FooResult lippincott(std::exception_ptr eptr) { assert(eptr!= nullptr); if (auto *ex = std::exception_ptr_cast<MyException1>(eptr)) { return FOO_ERROR1; } else if (auto *ex = std::exception_ptr_cast<MyException2>(eptr)) { return FOO_ERROR2; } else { if (auto *ex = std::exception_ptr_cast<std::exception>(eptr)) { log::warning("%s", ex->what()); } return FOO_UNKNOWN; } } try { foo::DoThing(); } catch (...) { return lippincott(std::current_exception()); }
    • Notes on the name exception_ptr_cast being redundant.
  • Danger of Calling with rvalue: It's dangerous to write if (auto *ex = std::exception_ptr_cast<std::exception>(std::current_exception())) { std::cout << ex->what() << "\n"; } as std::current_exception may copy the in-flight exception to storage that lives only as long as the exception_ptr's reference count remains above zero. MSVC may do this and it will compile everywhere but cause a use-after-free on Windows.
  • Suggested Solution and Its Wrongness: Suggested to make it ill-formed to call exception_ptr_cast with an rvalue exception_ptr by =deleteing the overload that preferentially binds to rvalues. But this is wrong as value category is not lifetime and we still want to be able to write code like if (Result r = DoThing(); r.has_error()) if (auto *ex = std::exception_ptr_cast<std::exception>(r.error())) std::cout << ex->what() << "\n; even when r.error() returns by value.
  • When is Deleting const&& Overloads Desirable: Short answer is never desirable as value category is not lifetime. The eleven places where (const&&)=delete appears in the STL today are in functions that return a pointer or reference to the argument itself. In the exception_ptr_cast case, it returns a pointer to the thing pointed to by the argument object and deleting the rvalue overload would break many things like in LLVM code. Examples include CI.getPCHContainerOperations(), Context.takeReplaceableUses(), CreateInfoOutputFile, etc. Deleting rvalue overloads is a bad way to deal with dangling bugs and we must preserve the ability to pass and return exception_ptrs by value.
阅读 10
0 条评论