Сообщение Re: Exception safe T Stack::pop() ? от 19.08.2018 20:39
Изменено 20.08.2018 5:45 N. I.
Re: Exception safe T Stack::pop() ?
Максим Рогожин:
МР>Можно ли сделать exception-safe T Stack::pop()?
Можно.
МР>Например, так:
Так будет пооптимальнее:
С вызовом деструктора будет примерно так:
МР>Можно ли сделать exception-safe T Stack::pop()?
Можно.
МР>Например, так:
Так будет пооптимальнее:
template<class T>
T Stack<T>::Pop() noexcept(std::is_nothrow_move_constructible_v<T>)
{
if (vused_ == 0)
internal_program_error("pop from empty stack");
try
{
return std::move_if_noexcept(v_[--vused_]);
}
catch (...)
{
++vused_;
throw;
}
}
С вызовом деструктора будет примерно так:
template <class F>
class scope_exit_wrapper
{
public:
scope_exit_wrapper(F &&f) :
m_f(std::forward<F>(f)) {}
~scope_exit_wrapper()
{
m_f();
}
scope_exit_wrapper(scope_exit_wrapper const &) = delete;
private:
F m_f;
};
template <class F>
class scope_success_wrapper
{
public:
scope_success_wrapper(F &&f) :
m_f(std::forward<F>(f)),
m_uncaught_exceptions(std::uncaught_exceptions())
{}
~scope_success_wrapper() noexcept(false)
{
if (std::uncaught_exceptions() == m_uncaught_exceptions)
m_f();
}
scope_success_wrapper(scope_success_wrapper const &) = delete;
private:
F m_f;
int m_uncaught_exceptions;
};
struct scope_exit_wrapper_arg_t {};
struct scope_success_wrapper_arg_t {};
template <class F>
scope_exit_wrapper<F> operator <<(scope_exit_wrapper_arg_t, F &&f)
{ return {std::forward<F>(f)}; }
template <class F>
scope_success_wrapper<F> operator <<(scope_success_wrapper_arg_t, F &&f)
{ return {std::forward<F>(f)}; }
#define PP_CONCAT_IMPL(x1, x2) x1##x2
#define PP_CONCAT(x1, x2) PP_CONCAT_IMPL(x1, x2)
#define SCOPE_EXIT(...) [[maybe_unused]] auto &&PP_CONCAT(SCOPE_SUCCESS_VAR_, __LINE__) = scope_exit_wrapper_arg_t() << [__VA_ARGS__]() noexcept -> void
#define SCOPE_SUCCESS(...) [[maybe_unused]] auto &&PP_CONCAT(SCOPE_SUCCESS_VAR_, __LINE__) = scope_success_wrapper_arg_t() << [__VA_ARGS__]() -> void
template<class T>
T Stack<T>::Pop() noexcept(std::is_nothrow_move_constructible_v<T>)
{
if (vused_ == 0)
internal_program_error("pop from empty stack");
if constexpr (std::is_nothrow_move_constructible_v<T>)
{
SCOPE_EXIT([&]{ v_[vused_].~T(); });
return std::move(v_[--vused_]);
}
else
{
SCOPE_SUCCESS([&]{ v_[--vused_].~T(); });
return v_[vused_ - 1];
}
}
Re: Exception safe T Stack::pop() ?
Максим Рогожин:
МР>Можно ли сделать exception-safe T Stack::pop()?
Можно.
МР>Например, так:
Так будет пооптимальнее:
С вызовом деструктора будет примерно так:
МР>Можно ли сделать exception-safe T Stack::pop()?
Можно.
МР>Например, так:
Так будет пооптимальнее:
template<class T>
T Stack<T>::Pop() noexcept(std::is_nothrow_move_constructible_v<T>)
{
if (vused_ == 0)
internal_program_error("pop from empty stack");
try
{
return std::move_if_noexcept(v_[--vused_]);
}
catch (...)
{
++vused_;
throw;
}
}
С вызовом деструктора будет примерно так:
template <class F>
class scope_exit_wrapper
{
public:
scope_exit_wrapper(F &&f) :
m_f(std::forward<F>(f)) {}
~scope_exit_wrapper()
{
m_f();
}
scope_exit_wrapper(scope_exit_wrapper const &) = delete;
private:
F m_f;
};
template <class F>
class scope_success_wrapper
{
public:
scope_success_wrapper(F &&f) :
m_f(std::forward<F>(f)),
m_uncaught_exceptions(std::uncaught_exceptions())
{}
~scope_success_wrapper() noexcept(false)
{
if (std::uncaught_exceptions() == m_uncaught_exceptions)
m_f();
}
scope_success_wrapper(scope_success_wrapper const &) = delete;
private:
F m_f;
int m_uncaught_exceptions;
};
struct scope_exit_wrapper_arg_t {};
struct scope_success_wrapper_arg_t {};
template <class F>
scope_exit_wrapper<F> operator <<(scope_exit_wrapper_arg_t, F &&f)
{ return {std::forward<F>(f)}; }
template <class F>
scope_success_wrapper<F> operator <<(scope_success_wrapper_arg_t, F &&f)
{ return {std::forward<F>(f)}; }
#define PP_CONCAT_IMPL(x1, x2) x1##x2
#define PP_CONCAT(x1, x2) PP_CONCAT_IMPL(x1, x2)
#define SCOPE_EXIT(...) [[maybe_unused]] auto &&PP_CONCAT(SCOPE_SUCCESS_VAR_, __LINE__) = scope_exit_wrapper_arg_t() << [__VA_ARGS__]() noexcept -> void
#define SCOPE_SUCCESS(...) [[maybe_unused]] auto &&PP_CONCAT(SCOPE_SUCCESS_VAR_, __LINE__) = scope_success_wrapper_arg_t() << [__VA_ARGS__]() -> void
template<class T>
T Stack<T>::Pop() noexcept(std::is_nothrow_move_constructible_v<T>)
{
if (vused_ == 0)
internal_program_error("pop from empty stack");
if constexpr (std::is_nothrow_move_constructible_v<T>)
{
SCOPE_EXIT(&){ v_[vused_].~T(); };
return std::move(v_[--vused_]);
}
else
{
SCOPE_SUCCESS(&){ v_[--vused_].~T(); };
return v_[vused_ - 1];
}
}