Upload
platonov-sergey
View
1.821
Download
6
Embed Size (px)
Citation preview
C++ WITHOUT EXCEPTIONS, PART 3
Alexey KutumovSenior software engineer at Kaspersky Lab
AGENDA
Зачем нужен C++ без исключений
Ограничения и проблемы
Решение проблем
…
Profit!
ЗАЧЕМ НУЖЕН C++ БЕЗ ИСКЛЮЧЕНИЙ
C++ БЕЗ ИСКЛЮЧЕНИЙ
try { throw std::logic_error(""); } catch (...) { // handle error }
error C2980: C++ exception handling is not supported with /kernel
C++ БЕЗ ИСКЛЮЧЕНИЙ
System programming
Game development
High-performance software (trading systems)
ОГРАНИЧЕНИЯ
ОГРАНИЧЕНИЯ
std::string message{"This string should be long enough..."};
ОГРАНИЧЕНИЯ
std::error_condition ec;nestl::string message{"This string should be long enough...", ec};if (ec) { // handle error}
ОГРАНИЧЕНИЯ
std::error_condition ec;nestl::string message{"This string should be long enough...", ec};if (ec) { // handle error}
nestl::string message2;message2 = message;
ОГРАНИЧЕНИЯ
std::error_condition ec;nestl::string message{"This string should be long enough...", ec};if (ec) { // handle error}
nestl::string message2;message2.assign_copy(message, ec);
ОГРАНИЧЕНИЯ
Есть исключения Нет исключенийОперация кидает исключение Операция возвращает ошибкуКонструктор копирования Двухфазная инициализацияОператор присваивания Явный метод копирования
ПРОБЛЕМЫ
ПРОБЛЕМЫ
С++ без исключений вынуждает программиста ослаблять инварианты
класса
ПРОБЛЕМЫ
struct MyClass { explicit MyClass(std::unique_ptr<Connection>&& connection) { if (!connection) { throw std::logic_error("connection is empty"); } m_connection = std::move(connection); }
std::unique_ptr<Connection> m_connection;};
ПРОБЛЕМЫ
С++ без исключений вынуждает программиста писать больше кода
ПРОБЛЕМЫ
#define TRY(expr) expr; if (ec) {return;}
// without exceptions
TRY(msg2.assign_copy(msg, ec));
TRY(Foo(msg, ec));TRY(Bar(msg2, ec));TRY(Baz(42, ec));
// with exceptions
msg2 = msg;
Foo(msg);Bar(msg2);Baz(42);
ПРОБЛЕМЫ
struct Message { nestl::string id; nestl::vector<int> data;
void assign_copy(const Message& other, std::error_condition& ec) { TRY(id.assign_copy(other.id, ec)); TRY(data.assign_copy(other.data, ec)); }};
FUTURE
compile-time reflection
magic_get (C++-14/C++-17) от Антона Полухина
CURRENT
noexcept (part of function type since C++-17)
std::move
std::is_nothrow_constructible (default, copy, move)
std::is_nothrow_assignable (copy, move)
std::is_nothrow_swappable (since C++-17)
NOEXCEPT PROPAGATION
struct SimpleData { SimpleData() noexcept : x(42) {}
int x;};
struct CompositeData { SimpleData d; float f;};
static_assert(std::is_nothrow_default_constructible_v<SimpleData>, "");static_assert(std::is_nothrow_default_constructible_v<CompositeData>, "");
ДЛЯ ЧЕГО НУЖНЫ TYPE_TRAITS
nestl::vector<Message> msgList;nestl::vector<CompositeData> dataList;
Message msg = get_message();CompositeData data = get_data();
std::error_condition ec;TRY(msgList.push_back_nothrow(msg, ec));TRY(dataList.push_back_nothrow(data, ec));
VECTOR::PUSH_BACK_NOTHROW
void push_back_nothrow(const value_type& val, std::error_condition& ec) { TRY(reallocate_nothrow(size() + 1, ec)); TRY(copy_construct_nothrow(data() + size(), val, ec));
this->m_last += 1;}
COPY_CONSTRUCT_NOTHROW
template <typename T>typename std::enable_if<std::is_nothrow_copy_constructible_v<T>>::typecopy_construct_nothrow(void* position, const T& val, std::error_condition& /* ec */) { new(position) T(val);}
template <typename T>
typename std::enable_if<!std::is_nothrow_copy_constructible_v<T>>::type
copy_construct_nothrow(void* position, const T& val, std::error_condition& ec) { T* obj = new(position) T(); // NOTE: default ctor obj->assign_copy(val, ec); if (ec) { obj->~T(); }}
C++ WITH EXCEPTIONS
library sources
Kernel mode driver
no exceptions
user mode application
has exceptions
EFI mode driver
no exceptions
C++ WITH EXCEPTIONS
struct Message { nestl::string id; nestl::vector<int> data;
void assign_copy(const Message& other, std::error_condition& ec) { TRY(id.assign_copy(other.id, ec)); TRY(data.assign_copy(other.data, ec)); }};
C++ WITH EXCEPTIONS
template <typename T>struct allocator { T* allocate(size_t count); // only if has exceptions void deallocate(T* location, size_t count); // only if has exceptions T* allocate_nothrow(size_t count) noexcept; void deallocate_nothrow(T* location, size_t count) noexcept;};
template <typename Allocator>struct allocator_traits { static pointer allocate(Allocator& a, size_t count); // only if has exceptions static pointer allocate_nothrow(Allocator& a, size_t count) noexcept;};
C++ WITH EXCEPTIONS
template <typename T, typename Allocator>struct vector_base { iterator begin();};
template <typename T, typename Allocator>struct vector_nx : public vector_base<T, Allocator> { void push_back_nothrow(const value_type& val, std::error_condition& ec) noexcept;};
template <typename T, typename Allocator>struct vector_x : public vector_nx<T, Allocator> { void push_back(const value_type& val);};
C++ WITH EXCEPTIONS
template <typename VectorBase>struct vector_nx : public VectorBase { void push_back_nothrow(const value_type& val, std::error_condition& ec) noexcept;};
template <typename VectorBase>struct vector_x : public VectorBase { void push_back(const value_type& val);};
C++ WITH EXCEPTIONS
struct system_exception_support : std::integral_constant<bool, NESTL_HAS_EXCEPTIONS == 1>{};
template <typename T, typename Allocator = nestl::allocator<T>>using vector = typename or_<system_exception_support::value, vector_x<T, Allocator>, vector_nx<T, Allocator>>::type;
LET'S [email protected]
https://github.com/prograholic/simple_vector