Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moveable but Non-Copyable Exceptions

I am thinking about writing non-copyable exception classes. I find it interesting, because then I don't have to worry about exceptions that could be thrown during allocations within the copy-constructor. If the creation of the exception object succeeds, everything is fine and there should be no issues with std::terminate.

struct exception
{
    exception() = default;
    exception(const exception&) = delete;
    exception(exception&&) noexcept = default;
    ~exception() noexcept = default;
    auto operator=(const exception&) -> exception& = delete;
    auto operator=(exception&&) noexcept -> exception& = delete;
};

int main()
{
    try {
        try {
            throw exception{};
        } catch (...) {
            std::rethrow_exception(
                std::current_exception());
        }
    } catch (const exception& e) {
        return 1;
    }
}

GCC-4.7 and Clang-3.2 accept the above code. However, I am a bit surprised. As far as I know, there are several situations where exception objects might be copied, e.g. std::current_exception() and std::rethrow_exception().

Question: Is the above code correct according to C++11, i.e. will it be accepted by all compilers conforming to C++11?

Edited: Added std::rethrow_exception and std::current_exception to the example. Both compilers accept this version. This should make it clear, that if the compiler doesn't require a copy-constructor when an exception is thrown, the compiler won't require one when these two functions are used.

like image 612
nosid Avatar asked Mar 13 '26 21:03

nosid


1 Answers

current_exception says it refers either to the current exception or to a copy of it it, but doesn't say which. This suggests to me that:

  • it is unspecified whether it is or not it's copied[*]
  • therefore, your exception class is not good (certainly not if anyone might call current_exception on it)
  • also therefore, it's no great surprise that it works in some implementations. There probably wouldn't be provision for the current exception not to be copied unless there was either demand for that from implementers or hope that implementers would avoid copies.

Just throwing the thing and catching it by reference is fine. The temporary in the throw expression is "used to initialize" the object used by the implementation to keep the current exception, so it can be moved or copied (according to which the class supports), and that move/copy can be elided.

For what it's worth, make_exception_ptr is specified to always copy. You could perhaps argue that this is a defect: e can be a by-value parameter in which case moving might be better. But that's my impetuous and ignorant impression, I've never even seen these functions before now.

[*] It's explicitly unspecified whether or not current_exception "creates a new copy each time it's called", but I'm not wholly certain whether that is intended to imply that it's unspecified whether it creates a new copy the first time it's called.

like image 55
Steve Jessop Avatar answered Mar 15 '26 10:03

Steve Jessop



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!