SlideShare a Scribd company logo
1 of 30
C++ WITHOUT EXCEPTIONS, PART 3
Alexey Kutumov
Senior 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>>::type
copy_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 TALK?
alexey.kutumov@gmail.com
https://github.com/prograholic/simple_vector

More Related Content

What's hot

Java AWT Calculadora
Java AWT CalculadoraJava AWT Calculadora
Java AWT Calculadorajubacalo
 
Java лаб13
Java лаб13Java лаб13
Java лаб13Enkhee99
 
JavaScript Assíncrono
JavaScript AssíncronoJavaScript Assíncrono
JavaScript AssíncronoNatã Barbosa
 
openFrameworks基礎 動きを生みだす、アニメーション入門 - 芸大グラフィックスプログラミング演習B
openFrameworks基礎 動きを生みだす、アニメーション入門 - 芸大グラフィックスプログラミング演習BopenFrameworks基礎 動きを生みだす、アニメーション入門 - 芸大グラフィックスプログラミング演習B
openFrameworks基礎 動きを生みだす、アニメーション入門 - 芸大グラフィックスプログラミング演習BAtsushi Tadokoro
 
Java осень 2012 лекция 6
Java осень 2012 лекция 6Java осень 2012 лекция 6
Java осень 2012 лекция 6Technopark
 
ECMAscript 2015 aka ES6 : à la découverte du nouveau javascript
ECMAscript 2015 aka ES6 : à la découverte du nouveau javascriptECMAscript 2015 aka ES6 : à la découverte du nouveau javascript
ECMAscript 2015 aka ES6 : à la découverte du nouveau javascriptmatparisot
 
JUG.ua 20170225 - Java bytecode instrumentation
JUG.ua 20170225 - Java bytecode instrumentationJUG.ua 20170225 - Java bytecode instrumentation
JUG.ua 20170225 - Java bytecode instrumentationAnton Arhipov
 
Java Thread Cronometro
Java Thread CronometroJava Thread Cronometro
Java Thread Cronometrojubacalo
 
c ++ informe Nº5 ucsm
c ++ informe Nº5 ucsmc ++ informe Nº5 ucsm
c ++ informe Nº5 ucsmIsaac Aquino
 
JAVA Program in NetBeans
JAVA Program in NetBeansJAVA Program in NetBeans
JAVA Program in NetBeansHimanshiSingh71
 
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016Loïc Knuchel
 
Ejb 3.0 Glassfish 2.X Netbeans 6.X
Ejb 3.0 Glassfish 2.X Netbeans 6.XEjb 3.0 Glassfish 2.X Netbeans 6.X
Ejb 3.0 Glassfish 2.X Netbeans 6.Xa19987225
 
珠三角技术沙龙新语言场 C++11
珠三角技术沙龙新语言场 C++11珠三角技术沙龙新语言场 C++11
珠三角技术沙龙新语言场 C++11翀 周
 
Александра Калинина "Trojan War: SinonJS"
Александра Калинина "Trojan War: SinonJS"Александра Калинина "Trojan War: SinonJS"
Александра Калинина "Trojan War: SinonJS"Fwdays
 
Шаблоны проектирования 2
Шаблоны проектирования 2Шаблоны проектирования 2
Шаблоны проектирования 2Constantin Kichinsky
 
C++ Programming - 13th Study
C++ Programming - 13th StudyC++ Programming - 13th Study
C++ Programming - 13th StudyChris Ohk
 
Writeup ctf online idsecconf 2017
Writeup ctf online idsecconf 2017Writeup ctf online idsecconf 2017
Writeup ctf online idsecconf 2017idsecconf
 
Corrig Projet P L S Q L
Corrig Projet  P L S Q LCorrig Projet  P L S Q L
Corrig Projet P L S Q Lbadirh
 

What's hot (20)

Java AWT Calculadora
Java AWT CalculadoraJava AWT Calculadora
Java AWT Calculadora
 
Java лаб13
Java лаб13Java лаб13
Java лаб13
 
JavaScript Assíncrono
JavaScript AssíncronoJavaScript Assíncrono
JavaScript Assíncrono
 
openFrameworks基礎 動きを生みだす、アニメーション入門 - 芸大グラフィックスプログラミング演習B
openFrameworks基礎 動きを生みだす、アニメーション入門 - 芸大グラフィックスプログラミング演習BopenFrameworks基礎 動きを生みだす、アニメーション入門 - 芸大グラフィックスプログラミング演習B
openFrameworks基礎 動きを生みだす、アニメーション入門 - 芸大グラフィックスプログラミング演習B
 
Java осень 2012 лекция 6
Java осень 2012 лекция 6Java осень 2012 лекция 6
Java осень 2012 лекция 6
 
ECMAscript 2015 aka ES6 : à la découverte du nouveau javascript
ECMAscript 2015 aka ES6 : à la découverte du nouveau javascriptECMAscript 2015 aka ES6 : à la découverte du nouveau javascript
ECMAscript 2015 aka ES6 : à la découverte du nouveau javascript
 
JUG.ua 20170225 - Java bytecode instrumentation
JUG.ua 20170225 - Java bytecode instrumentationJUG.ua 20170225 - Java bytecode instrumentation
JUG.ua 20170225 - Java bytecode instrumentation
 
Java Thread Cronometro
Java Thread CronometroJava Thread Cronometro
Java Thread Cronometro
 
c ++ informe Nº5 ucsm
c ++ informe Nº5 ucsmc ++ informe Nº5 ucsm
c ++ informe Nº5 ucsm
 
JAVA Program in NetBeans
JAVA Program in NetBeansJAVA Program in NetBeans
JAVA Program in NetBeans
 
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
 
Ejb 3.0 Glassfish 2.X Netbeans 6.X
Ejb 3.0 Glassfish 2.X Netbeans 6.XEjb 3.0 Glassfish 2.X Netbeans 6.X
Ejb 3.0 Glassfish 2.X Netbeans 6.X
 
珠三角技术沙龙新语言场 C++11
珠三角技术沙龙新语言场 C++11珠三角技术沙龙新语言场 C++11
珠三角技术沙龙新语言场 C++11
 
Danna y felix 10°
Danna y felix 10°Danna y felix 10°
Danna y felix 10°
 
Александра Калинина "Trojan War: SinonJS"
Александра Калинина "Trojan War: SinonJS"Александра Калинина "Trojan War: SinonJS"
Александра Калинина "Trojan War: SinonJS"
 
Proyecto Final Android-SQLite
Proyecto Final Android-SQLiteProyecto Final Android-SQLite
Proyecto Final Android-SQLite
 
Шаблоны проектирования 2
Шаблоны проектирования 2Шаблоны проектирования 2
Шаблоны проектирования 2
 
C++ Programming - 13th Study
C++ Programming - 13th StudyC++ Programming - 13th Study
C++ Programming - 13th Study
 
Writeup ctf online idsecconf 2017
Writeup ctf online idsecconf 2017Writeup ctf online idsecconf 2017
Writeup ctf online idsecconf 2017
 
Corrig Projet P L S Q L
Corrig Projet  P L S Q LCorrig Projet  P L S Q L
Corrig Projet P L S Q L
 

Viewers also liked

Антон Бикинеев, Reflection in C++Next
Антон Бикинеев,  Reflection in C++NextАнтон Бикинеев,  Reflection in C++Next
Антон Бикинеев, Reflection in C++NextSergey Platonov
 
Догнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_castДогнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_castRoman Orlov
 
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017Mikhail Matrosov
 
C++ Core Guidelines
C++ Core Guidelines C++ Core Guidelines
C++ Core Guidelines Sergey Zubkov
 
Фитнес для вашего кода: как держать его в форме
Фитнес для вашего кода: как держать его в формеФитнес для вашего кода: как держать его в форме
Фитнес для вашего кода: как держать его в формеIlia Shishkov
 
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловПолухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловSergey Platonov
 
Григорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптерГригорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптерSergey Platonov
 
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptСергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptSergey Platonov
 
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Platonov Sergey
 
Евгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализацияЕвгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализацияPlatonov Sergey
 

Viewers also liked (11)

Антон Бикинеев, Reflection in C++Next
Антон Бикинеев,  Reflection in C++NextАнтон Бикинеев,  Reflection in C++Next
Антон Бикинеев, Reflection in C++Next
 
Догнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_castДогнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_cast
 
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
 
C++ Core Guidelines
C++ Core Guidelines C++ Core Guidelines
C++ Core Guidelines
 
Фитнес для вашего кода: как держать его в форме
Фитнес для вашего кода: как держать его в формеФитнес для вашего кода: как держать его в форме
Фитнес для вашего кода: как держать его в форме
 
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловПолухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
 
Parallel STL
Parallel STLParallel STL
Parallel STL
 
Григорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптерГригорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптер
 
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptСергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
 
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
 
Евгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализацияЕвгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализация
 

More from Platonov Sergey

Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.Platonov Sergey
 
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на LinuxПавел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на LinuxPlatonov Sergey
 
Дмитрий Кашицын, Вывод типов в динамических и не очень языках II
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IIДмитрий Кашицын, Вывод типов в динамических и не очень языках II
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IIPlatonov Sergey
 
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IДмитрий Кашицын, Вывод типов в динамических и не очень языках I
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IPlatonov Sergey
 
QML\Qt Quick на практике
QML\Qt Quick на практикеQML\Qt Quick на практике
QML\Qt Quick на практикеPlatonov Sergey
 
Визуализация автомобильных маршрутов
Визуализация автомобильных маршрутовВизуализация автомобильных маршрутов
Визуализация автомобильных маршрутовPlatonov Sergey
 
Функциональный микроскоп: линзы в C++
Функциональный микроскоп: линзы в C++Функциональный микроскоп: линзы в C++
Функциональный микроскоп: линзы в C++Platonov Sergey
 
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...Platonov Sergey
 
HPX: C++11 runtime система для параллельных и распределённых вычислений
HPX: C++11 runtime система для параллельных и распределённых вычисленийHPX: C++11 runtime система для параллельных и распределённых вычислений
HPX: C++11 runtime система для параллельных и распределённых вычисленийPlatonov Sergey
 
Ranges calendar-novosibirsk-2015-08
Ranges calendar-novosibirsk-2015-08Ranges calendar-novosibirsk-2015-08
Ranges calendar-novosibirsk-2015-08Platonov Sergey
 
Использование maven для сборки больших модульных c++ проектов на примере Odin...
Использование maven для сборки больших модульных c++ проектов на примере Odin...Использование maven для сборки больших модульных c++ проектов на примере Odin...
Использование maven для сборки больших модульных c++ проектов на примере Odin...Platonov Sergey
 
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведенияДракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведенияPlatonov Sergey
 
One definition rule - что это такое, и как с этим жить
One definition rule - что это такое, и как с этим житьOne definition rule - что это такое, и как с этим жить
One definition rule - что это такое, и как с этим житьPlatonov Sergey
 
DI в C++ тонкости и нюансы
DI в C++ тонкости и нюансыDI в C++ тонкости и нюансы
DI в C++ тонкости и нюансыPlatonov Sergey
 
Аскетичная разработка браузера
Аскетичная разработка браузераАскетичная разработка браузера
Аскетичная разработка браузераPlatonov Sergey
 
Денис Кормалев Метаобъектная система Qt
Денис Кормалев Метаобъектная система QtДенис Кормалев Метаобъектная система Qt
Денис Кормалев Метаобъектная система QtPlatonov Sergey
 
Максим Хижинский Lock-free maps
Максим Хижинский Lock-free mapsМаксим Хижинский Lock-free maps
Максим Хижинский Lock-free mapsPlatonov Sergey
 
Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...
Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...
Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...Platonov Sergey
 

More from Platonov Sergey (20)

Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.
 
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на LinuxПавел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
 
Дмитрий Кашицын, Вывод типов в динамических и не очень языках II
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IIДмитрий Кашицын, Вывод типов в динамических и не очень языках II
Дмитрий Кашицын, Вывод типов в динамических и не очень языках II
 
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IДмитрий Кашицын, Вывод типов в динамических и не очень языках I
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
 
QML\Qt Quick на практике
QML\Qt Quick на практикеQML\Qt Quick на практике
QML\Qt Quick на практике
 
Визуализация автомобильных маршрутов
Визуализация автомобильных маршрутовВизуализация автомобильных маршрутов
Визуализация автомобильных маршрутов
 
Функциональный микроскоп: линзы в C++
Функциональный микроскоп: линзы в C++Функциональный микроскоп: линзы в C++
Функциональный микроскоп: линзы в C++
 
C++ exceptions
C++ exceptionsC++ exceptions
C++ exceptions
 
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
 
HPX: C++11 runtime система для параллельных и распределённых вычислений
HPX: C++11 runtime система для параллельных и распределённых вычисленийHPX: C++11 runtime система для параллельных и распределённых вычислений
HPX: C++11 runtime система для параллельных и распределённых вычислений
 
Ranges calendar-novosibirsk-2015-08
Ranges calendar-novosibirsk-2015-08Ranges calendar-novosibirsk-2015-08
Ranges calendar-novosibirsk-2015-08
 
Использование maven для сборки больших модульных c++ проектов на примере Odin...
Использование maven для сборки больших модульных c++ проектов на примере Odin...Использование maven для сборки больших модульных c++ проектов на примере Odin...
Использование maven для сборки больших модульных c++ проектов на примере Odin...
 
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведенияДракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
 
One definition rule - что это такое, и как с этим жить
One definition rule - что это такое, и как с этим житьOne definition rule - что это такое, и как с этим жить
One definition rule - что это такое, и как с этим жить
 
DI в C++ тонкости и нюансы
DI в C++ тонкости и нюансыDI в C++ тонкости и нюансы
DI в C++ тонкости и нюансы
 
Аскетичная разработка браузера
Аскетичная разработка браузераАскетичная разработка браузера
Аскетичная разработка браузера
 
Concepts lite
Concepts liteConcepts lite
Concepts lite
 
Денис Кормалев Метаобъектная система Qt
Денис Кормалев Метаобъектная система QtДенис Кормалев Метаобъектная система Qt
Денис Кормалев Метаобъектная система Qt
 
Максим Хижинский Lock-free maps
Максим Хижинский Lock-free mapsМаксим Хижинский Lock-free maps
Максим Хижинский Lock-free maps
 
Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...
Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...
Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...
 

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

Editor's Notes

  1. Добрый день, меня зовут Алексей Кутумов, я являюсь старшим разработчиком в ЛК
  2. Итак, вот примерный план моего рассказа.
  3. Что вообще это за зверь? Ну вообще-то, ничего сложного здесь нет. Просто означает, что мы не имеем права или не можем использовать некоторые конструкции языка. При этом компилятор, может нам помогать, например, вот так, как показано на слайде. Заметьте, объектами класса std::exception и его наследниками можно пользоваться. Но по факту они становятся бесполезны, так что про них забываем.
  4. Зачем вообще нужен C++ без исключений? Первое, что приходит на ум – системное программирование. Всякие драйвера для ОС. Например, виндовый компилятор запрещает использование исключений в коде драйверов, я показывал ошибку на предыдущем слайде. Но, при этом, он не запрещает использование C++! Также еще, game development, еще несколько лет назад для консолей компиляторы не имели поддержки исключений. Аналогично, требования к высокопрозводительным системам, иногда не позволяют использовать исключения. Особенно раньше, когда исключения были дорогими. К тому же, когда говорят, что исключения не влияют на производительность, на самом деле лукавят. Имеется ввиду, что основной путь в программе не проседает по производительности, но если мы решим бросить исключение, то здесь нас ждет сюрприз. Например, в винде, чтобы бросить исключение реализация C++ рантайма вызывает функцию __CxxThrowException, которая в свою очередь зовет системную функцию RaiseException, которая уходит в ядро. Понятно, что просто вернуть код ошибки в этом случае будет дешевле. Если кому-то интересно, я после доклада могу показать дизасм этих функций, чтобы убедиться наглядно. Кроме всего прочего, есть всякие coding convention, ограничения среды. Например, кидать исключения из динамических библиотек очень плохо, потому-что могут быть различия в рантайме приложения и самой библиотеки. На самом деле, в принципе, любому C++ объекту лучше не пересекать границы модулей, как раз из-за различия в рантайме, но об этом итак много где пишут и говорят. Если взять тот-же google, то у них тоже запрещены исключения, но по-другому – там throw – это std::abort. Такой подход, используется, например, в хромиуме.
  5. Вот мы потихоньку подходим к интересным вещам. Какие есть ограничения в C++ без исключений? Вопрос к залу.
  6. Какие есть проблемы в этом коде в среде без исключений? Ну, мы же здесь выделяем память. Что будет, если мы не сможем выделить память под нашу строку, ну, в обычном C++ у нас будет исключение. В среде без исключений этот код либо не скомпилируется, либо скорет ошибку аллокации памяти, что еще хуже. На самом деле, в прошлых докладах, посвященных теме C++ без исключений я показывал, что стандартная библиотека C++ по большей части не пригодна к использованию в такой среде. И я предлагал варианты, как можно задизайнить библиотеку для того, чтобы она могла работать в среде без исключений.
  7. Давайте пофантазируем. Например, наша библиотека может предоставлять вот такой конструктор, с error_condition. И мы бы смогли обработать ошибку аллокации. Но всегда ли этот подход нас спасет?
  8. У нас есть еще конструкторы копирования и операторы присваивания. С ними проблема заключается в том, что мы не можем поменять их сигнатуру. Если мы в конструктор копирования добавим еще аргумент, то он перестанет быть конструктором копирования, и будет каким-то другим конструктором. И при этом, компилятор попытается сгенерировать дефолтный конструктор копирования. То есть, то что раньше работало нам во благо, теперь оборачивается против нас. С оператором присваивания ситуация несколько иная, компилятор вообще нам запретит добавить еще один параметр в наш оператор. Так что все вот так плохо.
  9. Вместо этого, мы можем использовать например, вот такой метод assign_copy, который возвращает ошибку. Опять же, повторюсь. Мы сейчас с вами фантазируем, этого нет в стандартной библиотеке. Мы рассматриваем варианты, как это может быть реализовано.
  10. Здесь в таблице я привел способы преодоления этих ограничений. Обратите внимание, здесь мы говорим только об операциях, которые раньше могли бросить исключения. Кто может мне назвать теперь одну большую архитектурную проблему C++ без исключений?
  11. Озвученные ранее ограничения порождают проблемы, вот мы сейчас о них поговорим
  12. Есть самая серьезная проблема C++ без исключений, и с ней мы ничего не можем поделать. Навскидку, пример. Например, у вас есть класс, который содержит членом объект – ну, например, коннект к базе данных. В случае наличия исключений, вы в конструкторе своего класса сразу создаете коннект к БД, и если не получилось, то кидаете исключение. У вас получается инвариант – есть ваш объект жив, то коннект к БД создан. В случае отсутствия исключений, вы такой инвариант не сможете сделать никогда, ну просто никогда и никак. У вас нет механизма, чтобы запретить создание объекта, если какое-то условие нарушено. Вам придется всегда перед использованием вашего коннекта к БД проверять его на валидность (или сам объект должен это делать). Это действительно проблема, и решать ее приходится различными средствами – как средствами языка, выдумывать какие-то конструкции, макросы, которые делают двухфазную инициализацию, использовать фабрики объектов, так и сторонними средствами – например, кодогенерация, тестирование, ревью, использование статических анализаторов. Кстати, к чести последних, они могут очень хорошо осуществлять такие проверки, мы их используем, и они реально находят нам такие баги. Поэтому я всячески рекомендую их юзать.
  13. Вот пример, который демонстрирует мою мысль.
  14. Из приведенной ранее таблицы видно, что C++ без исключений вынуждает программиста писать больше кода, причем, по большей части код этот довольно противный, повторяющийся – код обработки ошибок, реализация методов assign_copy. Больше кода – больше багов. Как вы все знаете, компилятор генерирует довольно много кода – раскрутка стека при выходе из скоупа. Реализация стандартных операторов, конструкторов и деструкторов. Так вот в случае отсутствия исключений, программисту приходится выполнять работу компилятора. Вот всё оставшееся время мы будем бороться с этой проблемой.
  15. Давайте начнем с простых и наивных подходов – макросы. Вот мы попробовали частично решить эту проблему, сделали макрос, который позволяет нам минимизировать часть кода по проверке ошибки. Ну да, стало немного лучше.
  16. Здесь мы должны явно написать метод assign_copy, и еще не должны в нем ошибиться. Заметьте, что здесь компилятор нам ничем помочь не может, мы вынуждены делать эту работу за компилятор. Давайте подумаем, сможем ли мы как-то помочь компилятору в этом случае?
  17. Давайте посмотрим в будущее и поймем, что нам сможет помочь. На самом, деле, я очень жду compile time рефлексии, нам Антон Бикинеев про нее вчера рассказывал. Рефлексия поможет нам генерировать общий код. Например, мы сможем генерировать методы assign_copy автоматически для наших типов. На текущий момент для C++14 есть еще magic_get Антона Полухина, но он имеет много ограничений и нюансов. Возможно, magic_get и C++17 помогут нам облегчить наши страдания, пока не будет готова рефлексия. К сожалению Visual Studio 2015 не поддерживается библиотекой magic_get, возможно будущая 2017 студия будет поддерживаться.
  18. Теперь давайте обратимся к нашему компилятору и стандартной библиотеке. Хотя я говорил раньше, что большая часть стандартной библиотеки не работает в среде без исключений, тем не менее есть довольно полезные ее части – это type_traits. Итак, сначала давайте посмотрим на noexcept. Во-первых, это оператор, который в compile time выдает значение. Во-вторых, это спецификатор функции. Более того, с C++-17 этот спецификатор функции будет частью типа функции. Затем, move семантика. В среде без исключений ценности move семантики существенно возрастает. Более того, обычно мув конструктор и мув присваивание легко реализовать как noexcept. В общем это однозначный must-have. К тому же, в этом случае, компилятор играет за нас. Он легко и правильно геренирует нужные нам операторы и конструкторы. Еще раз повторюсь – это must have. Дальше – это type_traits – которые позволяют нам узнать, что объекты можно конструировать безопасно, копировать и присваивать. На самом деле, эти type_traits больше нужны разработчику библиотеку, нежели обычному программисту, мы позже посмотрим, как они нам пригодятся. Чем нам это может помочь, ну это же очевидно, если у нас есть безопасный оператор присваивания или конструктор копирования, то нам не нужно писать методы assign_copy, выполнять двухфазную инициализацию, у нас будут более строгие инварианты класса. В общем от noexcept и is_nothrow одни сплошные плюсы. Вот теперь, давайте поймем, как нам это может пригодиться.
  19. Небольшая ремарка про noexcept. Самое полезное в noexcept – это то, свойство noexcept наследуется при автогенерации операторов и конструкторов. Например, у нас есть нетривиальная реализация дефолтного конструктора Test1, если мы ее пометим noexcept, то и автосгенерённый конструктор Test2, тоже будет noexcept. Это очень важное и полезное свойство этого спецификатора. Почему же noexcept так важен в среде без исключений? Ну, вообще-то noexcept говорит о том, что ни при каких условиях исключение не вылетит из этой функции. А у нас здесь нет никаких исключений, получается он бессмысленный? Не совсем. Сейчас мы притянем noexcept к нашей проблеме. Все гуру C++ в один голос говорят, не меняйте семантику стандартных операторов и конструкторов, иначе, поведение ваших объектов в стандартной библиотеке будет очень странным. Например, оператор присваивания, в обычной среде он должен скопировать объект, или бросить исключение, если объект не скопирован. Теперь, если мы навешиваем noexcept, то мы как-бы говорим, что наша операция никогда не кинет исключение. А если вспомнить про семантику этого оператора, то это означает, что объект всегда успешно копируется, что нам и надо. И еще один момент. Вообще-говоря, если у вас код написан для среды без исключений, а вы компилируете его в среде с исключениями, то он не должен менять своего поведения. Согласитесь, будет очень неожиданно получить разное поведение одного и того-же кода. Вот как раз noexcept и является таким защитником
  20. Сейчас мы с вами говорили только про пользовательские типы. Но у нас же есть еще и разные контейнеры – векторы, списки, строки, и т.д. Поэтому важно рассмотреть их тоже. Вот здесь пример. У нас есть наша структура Message, мы делаем вектор этих структур и добавляем один элемент в конец. Вот я говорил, что type_traits нужны разработчику библиотеки, сейчас мы поймем для чего. Итак, кто может схематично рассказать, парой слов, как реализован метод push_back у стандартного вектора? Здесь у меня push_back_nothrow – по сути тоже самое.
  21. Я уже рассказывал про дизайн стандартной библиотеки для C++ без исключений, поэтому я не буду повторять этот доклад. Я всего лишь схематично покажу реализацию метода push_back_nothrow Итак, нам нужно реаллоцировать вектор, если это нужно. За это отвечает метод reallocate_nothrow. А затем, нам надо вставить новый элемент в конец используя операцию копирования. И после того, как все будет успешно, сдвигаем указатель и регистрируем наш объект в векторе.
  22. А вот как может выглядеть реализация операции копирования объекта. У нас есть область под объект. И в случае, если конструктор копирования noexcept, то используем его, в противном случае – зовем метод assign_copy. Тут на самом деле я забыл еще один момент, подсказка есть на слайде, кто его найдет? По хорошему, мне нужно проверить, что дефолтный конструктор тоже noexcept, иначе у нас могут быть проблемы. Смотрите, две эти функции обеспечивают копирование объекта, причем заметьте, что для noexcept конструктора все вообще тривиально. И мы не заставляем пользователя писать ненужный код метода assign_copy. Меньше кода – меньше багов )).
  23. Теперь давайте посмотрим на следующий пример: У нас есть некая библиотека, которая написана с учетом отсутствия исключений, и интерфейс этой библиотеки использует нашу структуру Message. Эта библиотека компилируется под три разных режима, при этом, для юзермодного приложения, она компилируется с исключениями, хоть и написана без них. В случае, когда эта библиотека используется в ядре и в EFI драйвере – тут вопросов нет, так же как нет и исключений. Но программисту юзермодного приложения теперь становится обидно. У меня есть исключения, почему же теперь я должен страдать, и использовать этот макрос TRY, std::error_condition. Вопрос вполне резонный. Если бы наш nestl::vector и nestl::string умели предоставлять требуемые операции в среде с исключениями, то юзермодному программисту было бы легко использовать эти вещи, и он даже бы не задумывался, об этих макросах и связанных с ними неудобствах.
  24. Вот наша структура, причем заметьте, если все члены этой структуры предоставляют нужные конструкторы и операторы, то компилятор сам сгенерирует их и для Message, а если их нет, то компилятор и не будет ничего делать. Значит, нам надо каким-то образом разрешить нужные операции для наших контейнеров, когда это можно сделать безопасно, и запретить их, если операции не имеют смысла. Итак, самый простой вариант обернуть эти методы в макрос. Так можно сделать, но мне много макросов не нравится. Можно сделать, чтобы в зависимости от среды
  25. Итак, вот давайте рассмотрим такой аллокатор. Отличие его от стандартного аллокатора заключается в том, что может быть реализована либо первая пара методов, либо вторая пара методов. Стандарт требует, чтобы была всегда первая пара методов. В зависимости от наличия исключений, реализации, могут быть реализованы и все 4 метода, а может только 2. И есть аллокатор трейтс, который расширяет возможности аллокатора. Этот трейт может реализовать недостающие методы (выразив один через другой). Заметьте, что первый статический метод этот трейт определит, только если есть исключения. То есть в среде без исключений, этот трейт будет предоставлять только второй метод. Как выразить одну реализацию через другую, я думаю проблем с этим нет. Чем данный трейт хорош, а тем, что он может адаптировать существующий std::allocator для наших контейнеров в среде с исключениями. По понятным причинам мы не можем юзать std::allocator в среде без исключений.
  26. Итак, мы делаем одну базовую реализацию, которая не зависит от исключений. Туда входит работа с внутренним представлением вектора, а также публичные методы. После этого, делаем реализацию вектора без исключений. И затем, расширяем реализацию, добавляя поддержку исключений. Обратите внимание, это еще не наш вектор, у них немного другие имена.
  27. Можно сделать немного по другому. Добавить еще один шаблонный шаблонный параметр. И тогда наши vector_ и vector_nx будут по сути обычными декораторами, и их можно будет применять к vector_base независимо.
  28. Ну и напоследок, мы собираем наш новый вектор. Я использовал первый вариант, когда vector_x расширяет vector_nx. Я ввожу новый trait, который позволяет узнать о наличии или отсутствии исключений. И конкретную реализацию вектора выбирать уже исходя из этого значения. Соответственно, vector_x и vector_nx - это две реализации вектора для разных сред. Заметьте, я не ввожу новый тип vector, вместо этого использую using, кто может сказать для чего я это делаю? Плюсы такого подхода заключаются в том, что vector будет иметь разные типы в среде с исключениями и в среде без исключений – это нам не даст сделать ошибки в правиле One Definition Rule, в случае, если мы случайно смешаем два объектника с разными значениями NESTL_HAS_EXCEPTIONS.