зеркало из
				https://github.com/iharh/notes.git
				synced 2025-11-03 23:26:09 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			227 строки
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			227 строки
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
void someFunc() noexcept; // more optimization opportunities
 | 
						||
 | 
						||
... maybe unwind a stack in case of exception (offers compiler writers more optimization opprotunities)...
 | 
						||
 | 
						||
 | 
						||
Ex 1.
 | 
						||
 | 
						||
If during mem-allocation one of the elt-move-ctor throws the exception, we just have a basic (not strong ex.guarantee).
 | 
						||
 | 
						||
For strong-guarantee, only non-throwing move acceptable
 | 
						||
std::vector::push_back uses std::move_if_noexcept
 | 
						||
-> cast to RVal only if T's move know to not throw.
 | 
						||
   ... or we don't have a copy c-tor (move c-tor can throw)
 | 
						||
 | 
						||
noexcept declaration is an INTERFACE promise (not just a current impl)
 | 
						||
 | 
						||
noexcept stands for
 | 
						||
  notexcept(true)
 | 
						||
 | 
						||
noexcept(false)
 | 
						||
  not guarantee not to throw
 | 
						||
 | 
						||
This is usefull for conditional ex-safety guarantee (at templates)
 | 
						||
 | 
						||
noexcept is also an operator:
 | 
						||
 | 
						||
tepmpate <typename T>
 | 
						||
void f(T && param) noexcept(noexcept(*param));
 | 
						||
 | 
						||
 | 
						||
****************
 | 
						||
* Alexandrescu *
 | 
						||
****************
 | 
						||
 | 
						||
std::promise<T>
 | 
						||
std::future<T>
 | 
						||
 | 
						||
template <class T> class Expected {
 | 
						||
    union {
 | 
						||
        T ham;
 | 
						||
        std::exception_ptr spam;
 | 
						||
    };
 | 
						||
    bool gotHam;
 | 
						||
    Expected() {} // used internally
 | 
						||
public:
 | 
						||
    Expected(const T& rhs)
 | 
						||
    :
 | 
						||
        ham(rhs), gotHam(true)
 | 
						||
    {
 | 
						||
    }
 | 
						||
 | 
						||
    Expected(T&& rhs)
 | 
						||
    :
 | 
						||
        ham(std::move(rhs)), gotHam(true)
 | 
						||
    {
 | 
						||
    }
 | 
						||
 | 
						||
    Expected(const Expected& rhs) : gotHam(rhs.gotHam) {
 | 
						||
        if (gotHam)
 | 
						||
            new(&ham) T(rhs.ham);
 | 
						||
        else
 | 
						||
            new(&spam) std::exception_ptr(rhs.spam);
 | 
						||
    }
 | 
						||
 | 
						||
    Expected(Expected&& rhs)
 | 
						||
    :
 | 
						||
        gotHam(rhs.gotHam)
 | 
						||
    {
 | 
						||
        if (gotHam)
 | 
						||
            new(&ham) T(std::move(rhs.ham));
 | 
						||
        else
 | 
						||
            new(&spam)
 | 
						||
        std::exception_ptr(std::move(rhs.spam));
 | 
						||
    }
 | 
						||
 | 
						||
    ~Expected()
 | 
						||
    {
 | 
						||
        using std::exception_ptr;
 | 
						||
        if (gotHam)
 | 
						||
            ham.~T();
 | 
						||
	else
 | 
						||
            spam.~exception_ptr();
 | 
						||
    }
 | 
						||
 | 
						||
    void swap(Expected& rhs)
 | 
						||
    {
 | 
						||
        if (gotHam)
 | 
						||
        {
 | 
						||
            if (rhs.gotHam)
 | 
						||
            {
 | 
						||
                using std::swap;
 | 
						||
                swap(ham, rhs.ham); // peek up this-namespace swap if available, otherwise - std::swap
 | 
						||
            }
 | 
						||
            else
 | 
						||
            {
 | 
						||
                auto t = std::move(rhs.spam);
 | 
						||
                new(&rhs.ham) T(std::move(ham));
 | 
						||
                new(&spam) std::exception_ptr(t);
 | 
						||
                std::swap(gotHam, rhs.gotHam);
 | 
						||
            }
 | 
						||
        }
 | 
						||
        else
 | 
						||
        {
 | 
						||
            if (rhs.gotHam)
 | 
						||
            {
 | 
						||
                rhs.swap(*this);
 | 
						||
            }
 | 
						||
            else
 | 
						||
            {
 | 
						||
                spam.swap(rhs.spam);
 | 
						||
                std::swap(gotHam, rhs.gotHam);
 | 
						||
            }
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    // Note: std::exception is thrown by value, but catch by reference (with d-tor and what() polymorphic stuff).
 | 
						||
    template <class E>
 | 
						||
    static Expected<T> fromException(const E& exception)
 | 
						||
    {
 | 
						||
        if (typeid(exception) != typeid(E))
 | 
						||
        {
 | 
						||
            throw std::invalid_argument("slicing detected");
 | 
						||
        }
 | 
						||
        return fromException(std::make_exception_ptr(exception));
 | 
						||
    }
 | 
						||
 | 
						||
    static Expected<T> fromException(std::exception_ptr p)
 | 
						||
    {
 | 
						||
        Expected<T> result;
 | 
						||
        result.gotHam = false;
 | 
						||
        new(&result.spam) std::exception_ptr(std::move(p));
 | 
						||
        return result;
 | 
						||
    }
 | 
						||
 | 
						||
    static Expected<T> fromException()
 | 
						||
    {
 | 
						||
        return fromException(std::current_exception());
 | 
						||
    }
 | 
						||
 | 
						||
    bool valid() const
 | 
						||
    {
 | 
						||
        return gotHam;
 | 
						||
    }
 | 
						||
 | 
						||
    T& get()
 | 
						||
    {
 | 
						||
        if (!gotHam)
 | 
						||
            std::rethrow_exception(spam);
 | 
						||
        return ham;
 | 
						||
    }
 | 
						||
 | 
						||
    const T& get() const
 | 
						||
    {
 | 
						||
        if (!gotHam)
 | 
						||
            std::rethrow_exception(spam);
 | 
						||
        return ham;
 | 
						||
    }
 | 
						||
 | 
						||
    template <class E>
 | 
						||
    bool hasException() const
 | 
						||
    {
 | 
						||
        try
 | 
						||
        {
 | 
						||
            if (!gotHam)
 | 
						||
                std::rethrow_exception(spam);
 | 
						||
        }
 | 
						||
        catch (const E& object)
 | 
						||
        {
 | 
						||
            return true;
 | 
						||
        }
 | 
						||
        catch (...)
 | 
						||
        {
 | 
						||
        }
 | 
						||
        return false;
 | 
						||
    }
 | 
						||
 | 
						||
    // auto r = Expected<string>::fromCode([] {
 | 
						||
    //     ...
 | 
						||
    // });
 | 
						||
    template <class F>
 | 
						||
    static Expected fromCode(F fun)
 | 
						||
    {
 | 
						||
        try
 | 
						||
        {
 | 
						||
            return Expected(fun());
 | 
						||
        }
 | 
						||
        catch (...)
 | 
						||
        {
 | 
						||
            return fromException();
 | 
						||
        }
 | 
						||
    }
 | 
						||
};
 | 
						||
 | 
						||
// Ex1
 | 
						||
Expected<int> parseInt(const std::string& s)
 | 
						||
{
 | 
						||
    int result;
 | 
						||
    ...
 | 
						||
    if (nonDigit)
 | 
						||
    {
 | 
						||
        return Expected<int>::fromException(std::invalid_argument("not a number"));
 | 
						||
    }
 | 
						||
    ...
 | 
						||
    if (tooManyDigits)
 | 
						||
    {
 | 
						||
        return Expected<int>::fromException(std::out_of_range("overflow"));
 | 
						||
    }
 | 
						||
    ...
 | 
						||
    return result;
 | 
						||
}
 | 
						||
 | 
						||
    // Caller
 | 
						||
    string s = readline();
 | 
						||
    auto x = parseInt(s).get(); // throw on error
 | 
						||
    auto y = parseInt(s); // won<6F>t throw
 | 
						||
    if (!y.valid())
 | 
						||
    {
 | 
						||
        // handle locally
 | 
						||
        if (y.hasException<std::invalid_argument>())
 | 
						||
	{
 | 
						||
            // no digits
 | 
						||
            ...
 | 
						||
        }
 | 
						||
        y.get(); // just "re"throw
 | 
						||
    }
 | 
						||
 |