30
C++ WITHOUT EXCEPTIONS, PART 3 Alexey Kutumov Senior software engineer at Kaspersky Lab

Алексей Кутумов, C++ без исключений, часть 3

Embed Size (px)

Citation preview

Page 1: Алексей Кутумов,  C++ без исключений, часть 3

C++ WITHOUT EXCEPTIONS, PART 3

Alexey KutumovSenior software engineer at Kaspersky Lab

Page 2: Алексей Кутумов,  C++ без исключений, часть 3

AGENDA

Зачем нужен C++ без исключений

Ограничения и проблемы

Решение проблем

Profit!

Page 3: Алексей Кутумов,  C++ без исключений, часть 3

ЗАЧЕМ НУЖЕН C++ БЕЗ ИСКЛЮЧЕНИЙ

Page 4: Алексей Кутумов,  C++ без исключений, часть 3

C++ БЕЗ ИСКЛЮЧЕНИЙ

try { throw std::logic_error(""); } catch (...) { // handle error }

error C2980: C++ exception handling is not supported with /kernel

Page 5: Алексей Кутумов,  C++ без исключений, часть 3

C++ БЕЗ ИСКЛЮЧЕНИЙ

System programming

Game development

High-performance software (trading systems)

Page 6: Алексей Кутумов,  C++ без исключений, часть 3

ОГРАНИЧЕНИЯ

Page 7: Алексей Кутумов,  C++ без исключений, часть 3

ОГРАНИЧЕНИЯ

std::string message{"This string should be long enough..."};

Page 8: Алексей Кутумов,  C++ без исключений, часть 3

ОГРАНИЧЕНИЯ

std::error_condition ec;nestl::string message{"This string should be long enough...", ec};if (ec) { // handle error}

Page 9: Алексей Кутумов,  C++ без исключений, часть 3

ОГРАНИЧЕНИЯ

std::error_condition ec;nestl::string message{"This string should be long enough...", ec};if (ec) { // handle error}

nestl::string message2;message2 = message;

Page 10: Алексей Кутумов,  C++ без исключений, часть 3

ОГРАНИЧЕНИЯ

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);

Page 11: Алексей Кутумов,  C++ без исключений, часть 3

ОГРАНИЧЕНИЯ

Есть исключения Нет исключенийОперация кидает исключение Операция возвращает ошибкуКонструктор копирования Двухфазная инициализацияОператор присваивания Явный метод копирования

Page 12: Алексей Кутумов,  C++ без исключений, часть 3

ПРОБЛЕМЫ

Page 13: Алексей Кутумов,  C++ без исключений, часть 3

ПРОБЛЕМЫ

С++ без исключений вынуждает программиста ослаблять инварианты

класса

Page 14: Алексей Кутумов,  C++ без исключений, часть 3

ПРОБЛЕМЫ

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;};

Page 15: Алексей Кутумов,  C++ без исключений, часть 3

ПРОБЛЕМЫ

С++ без исключений вынуждает программиста писать больше кода

Page 16: Алексей Кутумов,  C++ без исключений, часть 3

ПРОБЛЕМЫ

#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);

Page 17: Алексей Кутумов,  C++ без исключений, часть 3

ПРОБЛЕМЫ

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)); }};

Page 18: Алексей Кутумов,  C++ без исключений, часть 3

FUTURE

compile-time reflection

magic_get (C++-14/C++-17) от Антона Полухина

Page 19: Алексей Кутумов,  C++ без исключений, часть 3

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)

Page 20: Алексей Кутумов,  C++ без исключений, часть 3

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>, "");

Page 21: Алексей Кутумов,  C++ без исключений, часть 3

ДЛЯ ЧЕГО НУЖНЫ 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));

Page 22: Алексей Кутумов,  C++ без исключений, часть 3

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;}

Page 23: Алексей Кутумов,  C++ без исключений, часть 3

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(); }}

Page 24: Алексей Кутумов,  C++ без исключений, часть 3

C++ WITH EXCEPTIONS

library sources

Kernel mode driver

no exceptions

user mode application

has exceptions

EFI mode driver

no exceptions

Page 25: Алексей Кутумов,  C++ без исключений, часть 3

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)); }};

Page 26: Алексей Кутумов,  C++ без исключений, часть 3

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;};

Page 27: Алексей Кутумов,  C++ без исключений, часть 3

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);};

Page 28: Алексей Кутумов,  C++ без исключений, часть 3

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);};

Page 29: Алексей Кутумов,  C++ без исключений, часть 3

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;