SlideShare a Scribd company logo
C++ Core Guidelines
Сергей Зубков
Morgan Stanley
С благодарностями Бьярне Страуструпу
Zubkov - Guidelines - C++ Russia 2017 2
О чем это?
(и почему волнуется Rust?)
Что такое "Современный C++"?
• C++11, C++14, C++17, несколько технических
спецификаций (концепции, интервалы, сеть,
модули, корутины, и пр), множество новых
возможностей и подходов.
Правильный вопрос:
• Как выглядит хороший современный С++?
• Как он будет выглядеть в ближайшем будущем?
• Как сделать его доступным рядовым программистам, а
не экспертам из комитета?
Zubkov - Guidelines - C++ Russia 2017 3
Что такое "Современный C++"?
• Многие программисты (включая экспертов!)
• Пишут в устаревшем стиле, игнорируя 20+ лет прогресса и опыта
• Пишут в чужеродном стиле (как Java или как C)
• Путаются в деталях
• Наслаждаются деталями
- Доктор, мне больно, когда я так делаю!
- Так не делайте так!
Zubkov - Guidelines - C++ Russia 2017 4
Что такое "Современный C++"?
Как сделать современный C++ проще и доступнее?
• прямо сейчас!
• не создавая новый язык
• сохраняя совместимость
• cохраняя экспрессивную мощь
• сохраняя производительность
Три составные части нашего подхода:
Набор правил + Библиотека + Статический анализ
Zubkov - Guidelines - C++ Russia 2017 5
Набор правил + Библиотека + Статический анализ
В каждой компании уже есть набор правил для C++!
Типичные правила:
• Создаются в начале проекта/компании
• без опыта и наугад
• Устаревают
• обуза для пользователей / технический долг
• Узко специализированы
• применяются за пределами специализации
• Недостаточно объяснены
• требуют слепого подчинения или эксперта под рукой
• Носят запретительный характер
Zubkov - Guidelines - C++ Russia 2017 6
Набор правил + Библиотека + Статический анализ
Чем отличаются Core Guidelines?
• Современный С++ (и С++ ближайшего будущего)
• Каким вы хотите видеть новый код через пять лет?
• Предписания, не запрещения
• Плюс разъяснения достаточные для использования в обучении
• Не привязаны к конкретной компании
• Гитхаб под эгидой isocpp.org
• Анализаторы разрабатываются разными компаниями
• Центральные (“Core”)
• Компании и проекты могут включать и выключать группы правил (“профили”) и
дописывать/удалять индивидуальные правила по вкусу – и это уже реальность.
Zubkov - Guidelines - C++ Russia 2017 7
Набор правил + Библиотека + Статический анализ
Чем отличаются Core Guidelines?
Не только и не столько стиль программирования, в главные цели входят:
• Статическая типобезопасность
• Нет возможности обратиться к T как U
• Безопасность работы с памятью
• Нет доступа за пределы массива
• Гарантии времени жизни всех объектов
• Нет висячих указателей и ссылок
• Ресурсобезопасность
• Нет утечек ресурсов, включая утечки памяти
• В будущем - больше
Zubkov - Guidelines - C++ Russia 2017 8
Набор правил + Библиотека + Статический анализ
Не цели
• не минимальные
• не ортогональные
• не книга (и не учебник)
• не руководство по модернизации кода (хотя есть правила модернизации)
• не детальный список особых случаев (для этого есть стандарт)
• не подмножество языка (не теряет экспрессивность)
• не идеальные (сообщайте об ошибках)
Zubkov - Guidelines - C++ Russia 2017 9
Набор правил + Библиотека + Статический анализ
Правил много!
• Не все программисты смогут включить все правила
• Как минимум, не сразу: постепенная интеграция жизненно необходима
• Многим потребуется больше правил
• Для нетипичных ситуаций
• Наша цель: центральные правила (Core Guidelines)
• Правила для большинства
• Переход количества в качество:
• Нет утечкам ресурсов
• Нет висячим указателям
• Нет нарушениям типобезопасности
Zubkov - Guidelines - C++ Russia 2017 10
Набор правил + Библиотека + Статический анализ
“подмножество надмножества”
(изначально разработан для доменно-специфичных языков на основе С++)
• Нельзя запрещать без альтернатив
• Альтернатива – стандартная библиотека
• С дополнениями (потому что “прямо сейчас”)
Guidelines Support Library (https://github.com/Microsoft/GSL)
• Для необычных ситуаций – с собственными дополнениями (MyCompany Support Library)
• Авторы библиотеки могут пользоваться грязными/сложными/опасными
возможностями языка – для того они и существуют.
Цель: безопасная работа с массивами (без дополнительных проверок!)
Надмножество (библиотека): std::string_view, gsl::span, gsl::zstring
Подмножество (правила): не превращать массивы в указатели
не делать арифметику на указателях
не передавать указатель и размер
Zubkov - Guidelines - C++ Russia 2017 11
C++
GSL
Нельзя:
Стандартная
библиотека
Можно:
Набор правил + Библиотека + Статический анализ
Microsoft Visual Studio
LLVM Clang
Некоторые другие, близкие по духу, статические анализаторы также планируют
включить правила из Code Guidelines (например IFS Cevelop)
Zubkov - Guidelines - C++ Russia 2017 12
Набор правил + Библиотека + Статический анализ
Zubkov - Guidelines - C++ Russia 2017 13
Сколько ошибок в
этой программе?
Набор правил + Библиотека + Статический анализ
Zubkov - Guidelines - C++ Russia 2017 14
Набор правил + Библиотека + Статический анализ
Zubkov - Guidelines - C++ Russia 2017 15
Набор правил + Библиотека + Статический анализ
Zubkov - Guidelines - C++ Russia 2017 16
Набор правил
github.com/isocpp/CppCoreGuidelines
Zubkov - Guidelines - C++ Russia 2017 17
github.com/isocpp/CppCoreGuidelines
• 2014-2015: Morgan Stanley + Microsoft + ЦЕРН
• 13 сентября 2015 (CppCon15): на гитхабе
Принимайте участие!
Zubkov - Guidelines - C++ Russia 2017 18
Цели Core Guidelines
• Сделать целые классы ошибок невозможными
• Меньше времени в отладчике, меньше шансов для крахов и хаков
• Сделать невозможными утечки ресурсов
• Без потери производительности
• Сделать невозможными висячие указатели
• Без потери производительности
• Сделать невозможным выход за границы массива
• Без потери производительности
• Упростить
• Простой код проще поддерживать и проще преподавать
• Подальше от темных мест и экзотических приемов
• Программировать как эксперты
Zubkov - Guidelines - C++ Russia 2017 19
Секция P: Философия
• P.1: Express ideas directly in code
• P.2: Write in ISO Standard C++
• P.3: Express intent
• P.4: Ideally, a program should be statically type safe
• P.5: Prefer compile-time checking to run-time checking
• P.6: What cannot be checked at compile time should be checkable at run time
• P.7: Catch run-time errors early
• P.8: Don't leak any resources
• P.9: Don't waste time or space
• P.10: Prefer immutable data to mutable data
• P.11: Encapsulate messy constructs, rather than spreading through the code
Zubkov - Guidelines - C++ Russia 2017 20
Секция P: Философия
• P.1: Express ideas directly in code
• P.2: Write in ISO Standard C++
• P.3: Express intent
• P.4: Ideally, a program should be statically type safe
• P.5: Prefer compile-time checking to run-time checking
• P.6: What cannot be checked at compile time should be checkable at run time
• P.7: Catch run-time errors early
• P.8: Don't leak any resources
• P.9: Don't waste time or space
• P.10: Prefer immutable data to mutable data
• P.11: Encapsulate messy constructs, rather than spreading through the code
Смысл кода должен быть понятен из кода:
комментарии не компилируются!
change_speed(double s); // Что за double?
change_speed(2.3); // В каких единицах?
change_speed(Speed s); // ok: это новая скорость
change_speed(23_m / 10s); // ok: метры в секунду
change_speed(2.3); // ошибка компиляции
Zubkov - Guidelines - C++ Russia 2017 21
Секция P: Философия
• P.1: Express ideas directly in code
• P.2: Write in ISO Standard C++
• P.3: Express intent
• P.4: Ideally, a program should be statically type safe
• P.5: Prefer compile-time checking to run-time checking
• P.6: What cannot be checked at compile time should be checkable at run time
• P.7: Catch run-time errors early
• P.8: Don't leak any resources
• P.9: Don't waste time or space
• P.10: Prefer immutable data to mutable data
• P.11: Encapsulate messy constructs, rather than spreading through the code
Пишите на стандартном С++, запрещайте нестандартные
расширения языка. Когда они действительно нужны,
изолируйте от остального кода.
Для gcc и clang “-std=c++14” недостаточно!
Расширения отключаются ”-pedantic-errors”
Zubkov - Guidelines - C++ Russia 2017 22
Секция P: Философия
• P.1: Express ideas directly in code
• P.2: Write in ISO Standard C++
• P.3: Express intent
• P.4: Ideally, a program should be statically type safe
• P.5: Prefer compile-time checking to run-time checking
• P.6: What cannot be checked at compile time should be checkable at run time
• P.7: Catch run-time errors early
• P.8: Don't leak any resources
• P.9: Don't waste time or space
• P.10: Prefer immutable data to mutable data
• P.11: Encapsulate messy constructs, rather than spreading through the code
Код должен выражать цели, не средства
Плохо:
int i = 0;
while (i < v.size()) { /* работа с v[i] */ }
Лучше:
for (const auto& x : v) { /* работа с x */ } // порядок важен
for_each(par, v, [](int x) { /* работа с x */ }); // порядок неважен
Zubkov - Guidelines - C++ Russia 2017 23
Секция P: Философия
• P.1: Express ideas directly in code
• P.2: Write in ISO Standard C++
• P.3: Express intent
• P.4: Ideally, a program should be statically type safe
• P.5: Prefer compile-time checking to run-time checking
• P.6: What cannot be checked at compile time should be checkable at run time
• P.7: Catch run-time errors early
• P.8: Don't leak any resources
• P.9: Don't waste time or space
• P.10: Prefer immutable data to mutable data
• P.11: Encapsulate messy constructs, rather than spreading through the code
Статическая типобезопасность
(см также type safety profile)
std::variant вместо union
Нет преобразований массивов в указатели (см gsl::span)
Нет сужающих конверсий (см gsl::narrow_cast)
Нет кастов (явных приведений типов)
Никаких void* Zubkov - Guidelines - C++ Russia 2017 24
Секция P: Философия
• P.1: Express ideas directly in code
• P.2: Write in ISO Standard C++
• P.3: Express intent
• P.4: Ideally, a program should be statically type safe
• P.5: Prefer compile-time checking to run-time checking
• P.6: What cannot be checked at compile time should be checkable at run time
• P.7: Catch run-time errors early
• P.8: Don't leak any resources
• P.9: Don't waste time or space
• P.10: Prefer immutable data to mutable data
• P.11: Encapsulate messy constructs, rather than spreading through the code
Предпочитайте ошибки компиляции проверкам в коде
static_assert(sizeof(void*)==8, “64 bit required”);
static_assert(sizeof(VMPage) == PAGESIZE);
f(gsl::span<int>); // а не f(int*, int)
Zubkov - Guidelines - C++ Russia 2017 25
Секция P: Философия
• P.1: Express ideas directly in code
• P.2: Write in ISO Standard C++
• P.3: Express intent
• P.4: Ideally, a program should be statically type safe
• P.5: Prefer compile-time checking to run-time checking
• P.6: What cannot be checked at compile time should be checkable at run time
• P.7: Catch run-time errors early
• P.8: Don't leak any resources
• P.9: Don't waste time or space
• P.10: Prefer immutable data to mutable data
• P.11: Encapsulate messy constructs, rather than spreading through the code
Если нельзя сделать ошибкой компиляции, должна быть
возможность проверить в коде.
Контракты (см gsl_assert)
Исключения
Валидность указателя проверить невозможно!Zubkov - Guidelines - C++ Russia 2017 26
Секция P: Философия
• P.1: Express ideas directly in code
• P.2: Write in ISO Standard C++
• P.3: Express intent
• P.4: Ideally, a program should be statically type safe
• P.5: Prefer compile-time checking to run-time checking
• P.6: What cannot be checked at compile time should be checkable at run time
• P.7: Catch run-time errors early
• P.8: Don't leak any resources
• P.9: Don't waste time or space
• P.10: Prefer immutable data to mutable data
• P.11: Encapsulate messy constructs, rather than spreading through the code
Проверяйте ошибки как можно раньше
(идеально в конструкторах, чтобы не повторять проверки)
std::vector и gsl::span вместо массивов
gsl::not_null вместо указателей
Структуры и классы вместо строк
Zubkov - Guidelines - C++ Russia 2017 27
Секция P: Философия
• P.1: Express ideas directly in code
• P.2: Write in ISO Standard C++
• P.3: Express intent
• P.4: Ideally, a program should be statically type safe
• P.5: Prefer compile-time checking to run-time checking
• P.6: What cannot be checked at compile time should be checkable at run time
• P.7: Catch run-time errors early
• P.8: Don't leak any resources
• P.9: Don't waste time or space
• P.10: Prefer immutable data to mutable data
• P.11: Encapsulate messy constructs, rather than spreading through the code
Никаких утечек ресурсов – памяти, файлов, и т п.
RAII классы (std::vector, std::fstream, std::lock_guard)
std::make_unique/std::make_shared
gsl::finally
Никаких malloc/free/new/delete/strdup/fopen
Zubkov - Guidelines - C++ Russia 2017 28
Секция P: Философия
• P.1: Express ideas directly in code
• P.2: Write in ISO Standard C++
• P.3: Express intent
• P.4: Ideally, a program should be statically type safe
• P.5: Prefer compile-time checking to run-time checking
• P.6: What cannot be checked at compile time should be checkable at run time
• P.7: Catch run-time errors early
• P.8: Don't leak any resources
• P.9: Don't waste time or space
• P.10: Prefer immutable data to mutable data
• P.11: Encapsulate messy constructs, rather than spreading through the code
Эффективно используйте и память и процессор: это все-таки C++!
Всегда планируйте как минимум возможность оптимизации
(Per.7). Избегайте лишнего кода (знайте, что есть в библиотеках),
лишних проверок (см P.7 и правила об инвариантах),
избыточные структуры данных (от ненужных связных списков до
плохо упакованных структур).
Zubkov - Guidelines - C++ Russia 2017 29
Секция P: Философия
• P.1: Express ideas directly in code
• P.2: Write in ISO Standard C++
• P.3: Express intent
• P.4: Ideally, a program should be statically type safe
• P.5: Prefer compile-time checking to run-time checking
• P.6: What cannot be checked at compile time should be checkable at run time
• P.7: Catch run-time errors early
• P.8: Don't leak any resources
• P.9: Don't waste time or space
• P.10: Prefer immutable data to mutable data
• P.11: Encapsulate messy constructs, rather than spreading through the code
Предпочитайте константы и неизменяемые данные
Все что может быть constexpr или const, должно быть:
объекты,
методы,
ссылки и указатели.
(исключения – объекты, возвращаемые из функций)
Zubkov - Guidelines - C++ Russia 2017 30
Секция P: Философия
• P.1: Express ideas directly in code
• P.2: Write in ISO Standard C++
• P.3: Express intent
• P.4: Ideally, a program should be statically type safe
• P.5: Prefer compile-time checking to run-time checking
• P.6: What cannot be checked at compile time should be checkable at run time
• P.7: Catch run-time errors early
• P.8: Don't leak any resources
• P.9: Don't waste time or space
• P.10: Prefer immutable data to mutable data
• P.11: Encapsulate messy constructs, rather than spreading through the code
Прячьте грязный код в библиотеках за удобными интерфейсами,
и больше им не пользуйтесь.
Это опять принцип “подмножество надмножества”
в стандартной библиотеке масса примеров: union внутри
std::variant, указатели внутри std::vector и пр
Zubkov - Guidelines - C++ Russia 2017 31
Интерфейсы (фрагмент)
• I.1: Make interfaces explicit
• I.2: Avoid global variables
• I.3: Avoid singletons
• I.4: Make interfaces precisely and strongly typed
• I.5: State preconditions (if any)
• I.7: State postconditions
• I.10: Use exceptions to signal a failure to perform a required task
• I.11: Never transfer ownership by a raw pointer (T*)
• I.12: Declare a pointer that must not be null as not_null
• I.13: Do not pass an array as a single pointer
• I.24: Avoid adjacent unrelated parameters of the same type
• I.26: If you want a cross-compiler ABI, use a C-style subset
Zubkov - Guidelines - C++ Russia 2017 32
Интерфейсы (фрагмент)
• I.1: Make interfaces explicit
• I.2: Avoid global variables
• I.3: Avoid singletons
• I.4: Make interfaces precisely and strongly typed
• I.5: State preconditions (if any)
• I.7: State postconditions
• I.10: Use exceptions to signal a failure to perform a required task
• I.11: Never transfer ownership by a raw pointer (T*)
• I.12: Declare a pointer that must not be null as not_null
• I.13: Do not pass an array as a single pointer
• I.24: Avoid adjacent unrelated parameters of the same type
• I.26: If you want a cross-compiler ABI, use a C-style subset
Zubkov - Guidelines - C++ Russia 2017 33
Передача массива в виде одного указателя и даже в виде пары
аргументов (указатель и размер, указатели на начало и конец) –
источник ошибок. Размер массива не должен быть отделен от
самого массива.
Плохо:
void copy_n(const T* p, T* q, int n); // копия из [p:p+n) в [q:q+n)
Лучше:
void copy(gsl::span<const T> r, gsl::span<T> r2); // копия из r в r2
Интерфейсы (фрагмент)
• I.1: Make interfaces explicit
• I.2: Avoid global variables
• I.3: Avoid singletons
• I.4: Make interfaces precisely and strongly typed
• I.5: State preconditions (if any)
• I.7: State postconditions
• I.10: Use exceptions to signal a failure to perform a required task
• I.11: Never transfer ownership by a raw pointer (T*)
• I.12: Declare a pointer that must not be null as not_null
• I.13: Do not pass an array as a single pointer
• I.24: Avoid adjacent unrelated parameters of the same type
• I.26: If you want a cross-compiler ABI, use a C-style subset
Zubkov - Guidelines - C++ Russia 2017 34
Функции сообщают от ошибках исключениями
(“ошибка” – невозможность выполнить свою функцию,
гарантировать постусловие или восстановить инвариант).
int printf(const char* ...); // Плохо: возвращает код ошибки
template <class F, class ...Args>
explicit thread(F&& f, Args&&... args); // Лучше: бросает system_error
Функции (фрагмент)
Zubkov - Guidelines - C++ Russia 2017 35
• F.22: Use T* or owner<T*> or a smart pointer to designate a single object
• F.23: Use a not_null<T> to indicate "null" is not a valid value
• F.24: Use a span<T> or a span_p<T> to designate a half-open sequence
• F.25: Use a zstring or a not_null<zstring> to designate a C-style string
• F.26: Use a unique_ptr<T> to transfer ownership where a pointer is needed
• F.27: Use a shared_ptr<T> to share ownership
• F.44: Return a T& when copy is undesirable and "returning no object" isn't an option
• F.45: Don't return a T&&
• F.50: Use a lambda when a function won't do (to capture local variables, or to write a
local function)
• F.51: Where there is a choice, prefer default arguments over overloading
• F.52: Prefer capturing by reference in lambdas that will be used locally
Функции (фрагмент)
Zubkov - Guidelines - C++ Russia 2017 36
• F.22: Use T* or owner<T*> or a smart pointer to designate a single object
• F.23: Use a not_null<T> to indicate "null" is not a valid value
• F.24: Use a span<T> or a span_p<T> to designate a half-open sequence
• F.25: Use a zstring or a not_null<zstring> to designate a C-style string
• F.26: Use a unique_ptr<T> to transfer ownership where a pointer is needed
• F.27: Use a shared_ptr<T> to share ownership
• F.44: Return a T& when copy is undesirable and "returning no object" isn't an option
• F.45: Don't return a T&&
• F.50: Use a lambda when a function won't do (to capture local variables, or to write a
local function)
• F.51: Where there is a choice, prefer default arguments over overloading
• F.52: Prefer capturing by reference in lambdas that will be used locally
• gsl::not_null<T> (где T = U*, std::unique_ptr<U>, std::shared_ptr<U>),
гарантирует что T - не нулевой указатель. (см также I.12)
• Если параметр not_null, проверка в вызываемой функции не нужна
• Eсли результат not_null, проверка в вызывающей функции не нужна
int f(const int* p, gsl::not_null<const int*> q)
{
if(q) return *q; // бессмысленная проверка (F.23)
return *p; // опасный код! Голый указатель может быть нулевым (F.60)
}
Функции (фрагмент)
Zubkov - Guidelines - C++ Russia 2017 37
• F.22: Use T* or owner<T*> or a smart pointer to designate a single object
• F.23: Use a not_null<T> to indicate "null" is not a valid value
• F.24: Use a span<T> or a span_p<T> to designate a half-open sequence
• F.25: Use a zstring or a not_null<zstring> to designate a C-style string
• F.26: Use a unique_ptr<T> to transfer ownership where a pointer is needed
• F.27: Use a shared_ptr<T> to share ownership
• F.44: Return a T& when copy is undesirable and "returning no object" isn't an option
• F.45: Don't return a T&&
• F.50: Use a lambda when a function won't do (to capture local variables, or to write a
local function)
• F.51: Where there is a choice, prefer default arguments over overloading
• F.52: Prefer capturing by reference in lambdas that will be used locally
• Если есть возможность, пользуйтеся аргументами по умолчанию
вместо перегрузки функций: перегрузка – для похожих операций
над аргументами разных типов.
• Плохо: нет гарантии что код этих двух функций идентичен
void print(const string& s); // формат по умолчанию
void print(const string& s, format f);
• Лучше:
void print(const string& s, format f = {});
Параметры и аргументы (фрагмент)
Zubkov - Guidelines - C++ Russia 2017 38
Классы (фрагмент)
Zubkov - Guidelines - C++ Russia 2017 39
• C.2: Use class if the class has an invariant; use struct if the data members can vary
independently
• C.4: Make a function a member only if it needs direct access to the representation of a
class
• C.5: Place helper functions in the same namespace as the class they support
• C.20: If you can avoid defining any default operations, do
• C.21: If you define or =delete any default operation, define or =delete them all
• C.35: A base class with a virtual function needs a virtual destructor
• C.36: A destructor may not fail
• C.40: Define a constructor if a class has an invariant
• C.41: A constructor should create a fully initialized object
• C.42: If a constructor cannot construct a valid object, throw an exception
• C.43: Ensure that a class has a default constructor
• C.45: Prefer to use member initializers
Классы (фрагмент)
Zubkov - Guidelines - C++ Russia 2017 40
• C.2: Use class if the class has an invariant; use struct if the data members can vary
independently
• C.4: Make a function a member only if it needs direct access to the representation of a
class
• C.5: Place helper functions in the same namespace as the class they support
• C.20: If you can avoid defining any default operations, do
• C.21: If you define or =delete any default operation, define or =delete them all
• C.35: A base class with a virtual function needs a virtual destructor
• C.36: A destructor may not fail
• C.40: Define a constructor if a class has an invariant
• C.41: A constructor should create a fully initialized object
• C.42: If a constructor cannot construct a valid object, throw an exception
• C.43: Ensure that a class has a default constructor
• C.45: Prefer to use member initializers
• Конструктор устанавливает инвариант, функции-члены считают, что
инвариант гарантирован.
• Если данные можно менять напрямую, инвариант невозможен.
• struct Desc {
string left; // left и right могут меняться независимо друг от друга
string right; // инварианта нет
};
• class IntArray {
public:
// конструкторы, деструктор и пр
private:
gsl::owner<int*> beg; // инвариант: beg указывает на массив
int* end; // инвариант: end указывает на конец массива
};
Классы (фрагмент)
Zubkov - Guidelines - C++ Russia 2017 41
• C.2: Use class if the class has an invariant; use struct if the data members can vary
independently
• C.4: Make a function a member only if it needs direct access to the representation of a
class
• C.5: Place helper functions in the same namespace as the class they support
• C.20: If you can avoid defining any default operations, do
• C.21: If you define or =delete any default operation, define or =delete them all
• C.35: A base class with a virtual function needs a virtual destructor
• C.36: A destructor may not fail
• C.40: Define a constructor if a class has an invariant
• C.41: A constructor should create a fully initialized object
• C.42: If a constructor cannot construct a valid object, throw an exception
• C.43: Ensure that a class has a default constructor
• C.45: Prefer to use member initializers
• Стандартные конструкторы
• Делают возможным массивы и упрощают код
• Требуются для все регулярных типов
• Предоставляют состояние, которое можно использовать в
операциях перемещения
• class Date {
public:
Date(Day dd, Month mm, Year yyyy);
Date() = default; // См C.45
private:
int day = 1;
int month = 1;
int year = 1970;
};
std::vector<Date> vd(1000);
Наследование (фрагмент)
• C.121: If a base class is used as an interface, make it a pure abstract class
• C.126: An abstract class typically doesn't need a constructor
• C.127: A class with a virtual function should have a virtual or protected destructor
• C.128: Virtual functions should specify exactly one of virtual, override, or final
• C.131: Avoid trivial getters and setters
• C.132: Don't make a function virtual without reason
• C.133: Avoid protected data
• C.138: Create an overload set for a derived class and its bases with using
• C.140: Do not provide different default arguments for a virtual function and an overrider
• C.146: Use dynamic_cast where class hierarchy navigation is unavoidable
• C.147: Use dynamic_cast to a reference type when failure to find the required class is
considered an error
• C.152: Never assign a pointer to an array of derived class objects to a pointer to its base
Zubkov - Guidelines - C++ Russia 2017 42
Наследование (фрагмент)
• C.121: If a base class is used as an interface, make it a pure abstract class
• C.126: An abstract class typically doesn't need a constructor
• C.127: A class with a virtual function should have a virtual or protected destructor
• C.128: Virtual functions should specify exactly one of virtual, override, or final
• C.131: Avoid trivial getters and setters
• C.132: Don't make a function virtual without reason
• C.133: Avoid protected data
• C.138: Create an overload set for a derived class and its bases with using
• C.140: Do not provide different default arguments for a virtual function and an overrider
• C.146: Use dynamic_cast where class hierarchy navigation is unavoidable
• C.147: Use dynamic_cast to a reference type when failure to find the required class is
considered an error
• C.152: Never assign a pointer to an array of derived class objects to a pointer to its base
Zubkov - Guidelines - C++ Russia 2017 43
• Если в классе есть виртуальная функция, деструктор должет быть
виртуальными и доступным или невиртуальным и защищенным
• (удаление полиморфного класса с невиртуальным деструктором
через базовый указатель – неопределенное поведение)
• struct B {
virtual int f() = 0;
// деструктор по умолчанию доступный и невиртуальный
};
struct D : B { string s {"default"}; };
void use() {
std::unique_ptr<B> p = std::make_unique<D>();
} // Undefined Behavior (как минимум утечка памяти из-за строки)
Наследование (фрагмент)
• C.121: If a base class is used as an interface, make it a pure abstract class
• C.126: An abstract class typically doesn't need a constructor
• C.127: A class with a virtual function should have a virtual or protected destructor
• C.128: Virtual functions should specify exactly one of virtual, override, or final
• C.131: Avoid trivial getters and setters
• C.132: Don't make a function virtual without reason
• C.133: Avoid protected data
• C.138: Create an overload set for a derived class and its bases with using
• C.140: Do not provide different default arguments for a virtual function and an overrider
• C.146: Use dynamic_cast where class hierarchy navigation is unavoidable
• C.147: Use dynamic_cast to a reference type when failure to find the required class is
considered an error
• C.152: Never assign a pointer to an array of derived class objects to a pointer to its base
Zubkov - Guidelines - C++ Russia 2017 44
• Тривиальные геттеры и сеттеры не нужны
• // Плохо:
• class Point {
int x;
public:
int get_x() const { return x; }
void set_x(int xx) { x = xx; }
};
• // Лучше
• struct Point {
int x = 0;
}
Шаблоны (фрагмент)
• T.5: Combine generic and OO techniques to amplify their strengths, not their
costs
• T.61+T.62: Don’t over-parametrize
• T.64: Use specialization to provide alternative implementations of class templates
• T.65: Use tag dispatch to provide alternative implementations of functions
• T.67: Use specialization to provide alternative implementations for irregular types
• T.69: Inside a template, don't make an unqualified nonmember function call
unless you intend it to be a customization point
• #749 avoid recursion in variadic templates
• T.122: Use templates (usually template aliases) to compute types at compile time
• T.123: Use constexpr functions to compute values at compile time
• T.144: Don't specialize function templates
Zubkov - Guidelines - C++ Russia 2017 45
Шаблоны (фрагмент)
• T.5: Combine generic and OO techniques to amplify their strengths, not their
costs
• T.61+T.62: Don’t over-parametrize
• T.64: Use specialization to provide alternative implementations of class templates
• T.65: Use tag dispatch to provide alternative implementations of functions
• T.67: Use specialization to provide alternative implementations for irregular types
• T.69: Inside a template, don't make an unqualified nonmember function call
unless you intend it to be a customization point
• #749 avoid recursion in variadic templates
• T.122: Use templates (usually template aliases) to compute types at compile time
• T.123: Use constexpr functions to compute values at compile time
• T.144: Don't specialize function templates
Zubkov - Guidelines - C++ Russia 2017 46
• Излишняя параметризация – источник раздувания кода (даже
если компилятор поддерживает ICF).
• Если член шаблона зависит только от N параметров, он должен
быть в базовом классе, зависящем только от этих N параметров.
• // Плохо:
• template<typename T> class Foo { enum { v1, v2 }; … };
• // Лучше:
• struct Foo_base { enum { v1, v2 }; … };
template<typename T> class Foo : public Foo_base { … };
Шаблоны (фрагмент)
• T.5: Combine generic and OO techniques to amplify their strengths, not their
costs
• T.61+T.62: Don’t over-parametrize
• T.64: Use specialization to provide alternative implementations of class templates
• T.65: Use tag dispatch to provide alternative implementations of functions
• T.67: Use specialization to provide alternative implementations for irregular types
• T.69: Inside a template, don't make an unqualified nonmember function call
unless you intend it to be a customization point
• #749 avoid recursion in variadic templates
• T.122: Use templates (usually template aliases) to compute types at compile time
• T.123: Use constexpr functions to compute values at compile time
• T.144: Don't specialize function templates
Zubkov - Guidelines - C++ Russia 2017 47
• Рекурсия в шаблонном коде тормозит компиляцию. Ее можно
избежать при помощи fold expressions, constexpr функций,
std::index_sequence (std::invoke и т п) и просто pack expansions.
• // Плохо:
• template<class T> void pbv(vector<T>& v) {}
template<class T, class H, class... Ts>
void pbv(vector<T>& v, H&& h, Ts&&... Ts) {
v.push_back(h);
pbv(v, ts...);
}
• // Лучше
template<class T, class... Ts) void pbv(vector<T>& v, Ts&&... Ts) {
(v.push_back(ts), ...);
}
Профили
• Профиль – набор правил ставящих целью обеспечить конкретную
гарантию.
• Type safety (типобезопасность)
• Bounds safety (безопасность работы с массивами)
• Lifetime safety (гарантии времени жизни объектов)
• В будущем – arithmetic, concurrency, noexcept, noalloc, etc.
Zubkov - Guidelines - C++ Russia 2017 48
Профиль типобезопасности
• P.4: Ideally, a program should be statically type safe
• C.183: Don't use a union for type punning
• Type.1: Don't use reinterpret_cast
• Type.2: Don't use static_cast downcasts. Use dynamic_cast instead
• Type.3: Don't use const_cast to cast away const (i.e., at all)
• Type.4: Don't use C-style (T)expression casts that would perform a
static_cast downcast, const_cast, or reinterpret_cast
• Type.5: Don't use a variable before it has been initialized
• Type.6: Always initialize a member variable
Zubkov - Guidelines - C++ Russia 2017 49
Массивы и Указатели (Bounds Profile)
• ES.55: Avoid the need for range checking
• Bounds.1: Don't use pointer arithmetic. Use span instead.
• Bounds.2: Only index into arrays using constant expressions.
• Bounds.3: No array-to-pointer decay.
• Bounds.4: Don't use standard library functions and types that are not
bounds-checked.
Zubkov - Guidelines - C++ Russia 2017 50
Контроль времени жизни объектов
(Lifetime Profile)
1. У каждого объекта есть только один владелец
2. На объект могут ссылаться много ссылок/указателей
3. Никакая ссылка/указатель не может пережить владельца
• Правила для обычной функции:
• Не показывать ссылку/указатель на локальную переменную тому кто вызвал
• Ссылка/указатель переданная как аргумент может быть возвращена
• Указатель от new может быть возвращен если мы сообщим что этот указатель – владелец
int* f(int* p) {
int x = 4;
return &x; // Ошибка
return new int{7}; // OK, только надо отметить что это - владелец
return p; // OK: откуда пришло, туда и вернется
}
Zubkov - Guidelines - C++ Russia 2017 51
Контроль времени жизни объектов
(Lifetime Profile)
• Как отмечать владельцев?
• Предпочтительно: std::unique_ptr, std::vector, std::map, std::shared_ptr,
• На низком уровне (например внутри std::vector<T>): gsl::owner<T>
template<class T> using owner = T;
• Этот низкоуровневый owner существует только на уровне системы типов и
статического анализа, в компилированном коде он неотличим от T
vector<int*> f(int* p)
{
owner<int*> q = new int{7};
vector<int*> res = {p, q}; // OK: копия q – не владелец
return res; // Ошибка: владелец должен быть возвращен или удален
}
Zubkov - Guidelines - C++ Russia 2017 52
Правила будущего
• T.10/I.9: Specify concepts for all template arguments
• T.11: Whenever possible use standard concepts
• T.12: Prefer concept names over auto for local variables
• T.13: Prefer the shorthand notation for simple, single-type argument concepts
• T.20: Avoid "concepts" without meaningful semantics
• T.21: Require a complete set of operations for a concept
• T.22: Specify axioms for concepts
• T.23: Differentiate a refined concept from its more general case by adding new use patterns
• T.24: Use tag classes or traits to differentiate concepts that differ only in semantics
• T.25: Avoid complementary constraints
• T.26: Prefer to define concepts in terms of use-patterns rather than simple syntax
• T.30+31: Use !C<T> / C1<T> || C2<T> sparingly
• I.6+8: Prefer Expects() for expressing preconditions/ Ensures() for expressing postconditions
Zubkov - Guidelines - C++ Russia 2017 53
См также http://stroustrup.com/good_concepts.pdf
Не-правила и мифы
• NR.1: Don't: All declarations should be at the top of a function
• NR.2: Don't: Have only a single return-statement in a function
• NR.3: Don't: Don't use exceptions
• NR.4: Don't: Place each class declaration in its own source file
• NR.5: Don't: Don't do substantive work in a constructor; instead use
two-phase initialization
• NR.6: Don't: Place all cleanup actions at the end of a function and
goto exit
• NR.7: Don't: Make all data members protected
Zubkov - Guidelines - C++ Russia 2017 54
Слишком много правил?
• Эти правила для всех:
• Новичков, экспертов, библиотек, системщиков, обычных и необычных
приложений
• Никто не предлагает выучить все эти правила!
• Никто не предлагает даже прочитать все эти правила!
• Подавляющее большинство правил предназначено для
анализаторов:
• Анализ отметит возможное нарушение и покажет какое правило
прочитать:
•
Zubkov - Guidelines - C++ Russia 2017 55
Мы хотим хороший современный С++
• “Мы” значит “вы”
• это не под силу одному человеку или одной компании
• Каким вы хотите видеть код через 5 лет?
• “Таким же как и сегодня” – не ответ
• Модернизировать много кода – нелегко
• Если ясна цель – можно к ней двигаться
• Не все согласны с тем как выглядит хороший С++
• Код не должен выглядеть одинакого
• Но должно быть общее ядро
• Нужно обсуждать и применять правила и анализаторы
• Помогайте!
• Нужны правила, анализ, комментарии, редакторы
https://github.com/isocpp/CppCoreGuidelines
Zubkov - Guidelines - C++ Russia 2017 56
Zubkov - Guidelines - C++ Russia 2017 57
extras
Zubkov - Guidelines - C++ Russia 2017 58
Обработка ошибок (фрагмент)
• E.1: Develop an error-handling strategy early in a design
• E.2: Throw an exception to signal that a function can't perform its assigned task
• E.3: Use exceptions for error handling only
• E.5: Let a constructor establish an invariant, and throw if it cannot
• E.12: Use noexcept when exiting a function because of a throw is impossible or unacceptable
• E.13: Never throw while being the direct owner of an object
• E.14: Use purpose-designed user-defined types as exceptions (not built-in types)
• E.15: Catch exceptions from a hierarchy by reference
• E.16: Destructors, deallocation, and swap must never fail
• E.17: Don't try to catch every exception in every function
• E.18: Minimize the use of explicit try/catch
• E.19: Use a final_action object to express cleanup if no suitable resource handle is available
Zubkov - Guidelines - C++ Russia 2017 59
Многозадачность (избранное)
• CP.4: Think in terms of tasks, rather than threads
• CP.8: Don't try to use volatile for synchronization
• CP.20+21: Use RAII, never plain lock()/unlock() / Use std::lock() to acquire multiple mutexes
• CP.22: Never call unknown code while holding a lock (e.g., a callback)
• CP.23+24: Think of a joining thread as a scoped container / a detached thread as a global container
• CP.25+26: Prefer gsl::raii_thread / gsl::detached_thread
• CP.31: Pass small amounts of data between threads by value, rather than by reference or pointer
• CP.32: To share ownership between unrelated threads use shared_ptr
• CP.42: Don't wait without a condition
• CP.50: Define a mutex together with the data it protects
• Use algorithms that are designed for parallelism, not algorithms with unnecessary dependency on linear
evaluation
• CP.60: Use a future to return a value from a concurrent task
• CP.100: Don't use lock-free programming unless you absolutely have to
Zubkov - Guidelines - C++ Russia 2017 60
Управление ресурсами
• R.1: Manage resources automatically using resource handles and RAII
• R.3: A raw pointer (a T*) is non-owning
• R.4: A raw reference (a T&) is non-owning
• R.5: Prefer scoped objects
• R.10+11: Avoid malloc() and free() / Avoid calling new and delete explicitly
• R.12: Immediately give the result of an explicit resource allocation to a manager object
• R.13: Perform at most one explicit resource allocation in a single expression statement
• R.15: Always overload matched allocation/deallocation pairs
• R.20: Use unique_ptr or shared_ptr to represent ownership
• R.21: Prefer unique_ptr over shared_ptr unless you need to share ownership
• R.22+23: Use make_shared() to make shared_ptrs / make_unique() to make unique_ptrs
• R.30: Take smart pointers as parameters only to explicitly express lifetime semantics
Zubkov - Guidelines - C++ Russia 2017 61
Выражения и инструкции (избранное)
• ES.5: Keep scopes small
• ES.11: Use auto to avoid redundant repetition of type names
• ES.20: Always initialize an object
• ES.21+22: Don't introduce a variable (or constant) before you need to use it / until you have a
value to initialize it with
• ES.23: Prefer the {}-initializer syntax
• ES.24: Use a unique_ptr<T> to hold pointers in code that may throw
• ES.26: Don't use a variable for two unrelated purposes
• ES.28: Use lambdas for complex initialization, especially of const variables
• ES.30+31: Don't use macros for program text manipulation / for constants or "functions"
• ES.45: Avoid narrowing conversions
• ES.48: Avoid casts
• ES.56: Avoid std::move() in application code
• ES.63: Don't slice
Zubkov - Guidelines - C++ Russia 2017 62
const
• P.10: Prefer immutable data to mutable data
• ES.25: Declare an object const or constexpr unless you want to modify its value
later on
• ES.50: Don't cast away const
• F.4: If a function may have to be evaluated at compile time, declare it constexpr
• R.6: Avoid non-const global variables
• Con.1: By default, make objects immutable
• Con.2: By default, make member functions const
• Con.3: By default, pass pointers and references to consts
• Con.4: Use const to define objects with values that do not change after
construction
• Con.5: Use constexpr for values that can be computed at compile time
Zubkov - Guidelines - C++ Russia 2017 63

More Related Content

PPTX
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
PPTX
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
PPTX
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
PPTX
Евгений Зуев, С++ в России: Стандарт языка и его реализация
PDF
Для чего мы делали свой акторный фреймворк и что из этого вышло?
PDF
Павел Довгалюк, Обратная отладка
PPTX
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
PDF
Андрей Карпов, Приватные байки от разработчиков анализатора кода
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Евгений Зуев, С++ в России: Стандарт языка и его реализация
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Павел Довгалюк, Обратная отладка
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
Андрей Карпов, Приватные байки от разработчиков анализатора кода

What's hot (20)

PPTX
SWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотек
PDF
Цена ошибки
PDF
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
PDF
Шишки, набитые за 15 лет использования акторов в C++
PDF
Борис Сазонов, RAII потоки и CancellationToken в C++
PPTX
Основы и применение статического анализа кода при разработке лекция 1
PPTX
Асинхронность и сопрограммы
PDF
Python и Cython
PDF
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
PPTX
разработка бизнес приложений (8)
PDF
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
PDF
Дизайн больших приложений в ФП
PPTX
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
PDF
Олег Бартунов и Иван Панченко
PPT
C# 5.0. Взгляд в будущее
PPT
Anti-fraud solutions in RTB / Вадим Антонюк (IPONWEB)
PDF
WebCamp 2016: Python.Максим Климишин.Типизированный Python
PDF
Модель акторов и C++ что, зачем и как?
PPTX
Оптимизация высоконагруженных ASP.NET приложений, работающих с MS SQL Server ...
PDF
WebCamp2016:Front-End.Максим Климишин.Теоретические и практические концепции ...
SWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотек
Цена ошибки
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Шишки, набитые за 15 лет использования акторов в C++
Борис Сазонов, RAII потоки и CancellationToken в C++
Основы и применение статического анализа кода при разработке лекция 1
Асинхронность и сопрограммы
Python и Cython
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
разработка бизнес приложений (8)
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Дизайн больших приложений в ФП
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
Олег Бартунов и Иван Панченко
C# 5.0. Взгляд в будущее
Anti-fraud solutions in RTB / Вадим Антонюк (IPONWEB)
WebCamp 2016: Python.Максим Климишин.Типизированный Python
Модель акторов и C++ что, зачем и как?
Оптимизация высоконагруженных ASP.NET приложений, работающих с MS SQL Server ...
WebCamp2016:Front-End.Максим Климишин.Теоретические и практические концепции ...
Ad

Viewers also liked (20)

PDF
Антон Бикинеев, Reflection in C++Next
PPTX
Алексей Кутумов, C++ без исключений, часть 3
PPTX
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
PDF
Parallel STL
PPTX
Григорий Демченко, Универсальный адаптер
PDF
Догнать и перегнать boost::lexical_cast
PPTX
Mixing C++ & Python II: Pybind11
PDF
C++Now Trip Report
PPTX
Battle: BDD vs notBDD
PPTX
Benchmark it
PDF
Restinio - header-only http and websocket server
PDF
Actors for fun and profit
PPTX
Ускоряем сборку С++ проектов. Практика использования unity-сборок
PPTX
Analysis and interpretation of monitoring data
PDF
(Не)чёткий поиск
PPTX
C++ and Assembly: Debugging and Reverse Engineering
PDF
MxxRu::externals: Repositoryless Dependency Manager
PPTX
C++ в играх, больших и не очень
PDF
The beast is becoming functional
PPTX
Поиск уязвимостей с использованием статического анализа кода
Антон Бикинеев, Reflection in C++Next
Алексей Кутумов, C++ без исключений, часть 3
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Parallel STL
Григорий Демченко, Универсальный адаптер
Догнать и перегнать boost::lexical_cast
Mixing C++ & Python II: Pybind11
C++Now Trip Report
Battle: BDD vs notBDD
Benchmark it
Restinio - header-only http and websocket server
Actors for fun and profit
Ускоряем сборку С++ проектов. Практика использования unity-сборок
Analysis and interpretation of monitoring data
(Не)чёткий поиск
C++ and Assembly: Debugging and Reverse Engineering
MxxRu::externals: Repositoryless Dependency Manager
C++ в играх, больших и не очень
The beast is becoming functional
Поиск уязвимостей с использованием статического анализа кода
Ad

Similar to C++ Core Guidelines (20)

PDF
Плюсы и минусы Go для разработчиков на C++, Вячеслав Бахмутов
PPTX
Как развивать библиотеку компонентов, не ломая ее / Артур Удалов (Mail.Ru Group)
PDF
Виталий Шибаев - Креативный менеджмент глазами разработчика: как выжить в agi...
PDF
"Девопс - это не только для программистов. Практические примеры из жизни одно...
PDF
Профессиональная разработка в суровом Enterprise
PPTX
DevOps для 1С
PDF
Плюсы и минусы Go для разработчиков на C++, Вячеслав Бахмутов
PDF
Алексей Лустин. Непрерывная проверка качества кода.
PPTX
Daemons In Web on #devrus
PDF
Workflow: работа над проектом в Яндексе
PDF
Денис Чистяков: Workflow. Работа над проектом в Яндексе
PDF
Как разраба
PDF
Юрий Василевский «Автоматизация в XCode»
PDF
Юрий Василевский "Автоматизация в XCode"
PDF
Devconf 2011 - PHP - Как разрабатывается фреймворк Yii
PDF
PPTX
13 октября, DEV {web} - конференция о Highload веб-разработке. "Управление ок...
PPTX
Little Service in 2h
PDF
Проходим тест Джоэла
PPTX
Лучшие практики на практике
Плюсы и минусы Go для разработчиков на C++, Вячеслав Бахмутов
Как развивать библиотеку компонентов, не ломая ее / Артур Удалов (Mail.Ru Group)
Виталий Шибаев - Креативный менеджмент глазами разработчика: как выжить в agi...
"Девопс - это не только для программистов. Практические примеры из жизни одно...
Профессиональная разработка в суровом Enterprise
DevOps для 1С
Плюсы и минусы Go для разработчиков на C++, Вячеслав Бахмутов
Алексей Лустин. Непрерывная проверка качества кода.
Daemons In Web on #devrus
Workflow: работа над проектом в Яндексе
Денис Чистяков: Workflow. Работа над проектом в Яндексе
Как разраба
Юрий Василевский «Автоматизация в XCode»
Юрий Василевский "Автоматизация в XCode"
Devconf 2011 - PHP - Как разрабатывается фреймворк Yii
13 октября, DEV {web} - конференция о Highload веб-разработке. "Управление ок...
Little Service in 2h
Проходим тест Джоэла
Лучшие практики на практике

C++ Core Guidelines

  • 1. C++ Core Guidelines Сергей Зубков Morgan Stanley С благодарностями Бьярне Страуструпу
  • 2. Zubkov - Guidelines - C++ Russia 2017 2 О чем это? (и почему волнуется Rust?)
  • 3. Что такое "Современный C++"? • C++11, C++14, C++17, несколько технических спецификаций (концепции, интервалы, сеть, модули, корутины, и пр), множество новых возможностей и подходов. Правильный вопрос: • Как выглядит хороший современный С++? • Как он будет выглядеть в ближайшем будущем? • Как сделать его доступным рядовым программистам, а не экспертам из комитета? Zubkov - Guidelines - C++ Russia 2017 3
  • 4. Что такое "Современный C++"? • Многие программисты (включая экспертов!) • Пишут в устаревшем стиле, игнорируя 20+ лет прогресса и опыта • Пишут в чужеродном стиле (как Java или как C) • Путаются в деталях • Наслаждаются деталями - Доктор, мне больно, когда я так делаю! - Так не делайте так! Zubkov - Guidelines - C++ Russia 2017 4
  • 5. Что такое "Современный C++"? Как сделать современный C++ проще и доступнее? • прямо сейчас! • не создавая новый язык • сохраняя совместимость • cохраняя экспрессивную мощь • сохраняя производительность Три составные части нашего подхода: Набор правил + Библиотека + Статический анализ Zubkov - Guidelines - C++ Russia 2017 5
  • 6. Набор правил + Библиотека + Статический анализ В каждой компании уже есть набор правил для C++! Типичные правила: • Создаются в начале проекта/компании • без опыта и наугад • Устаревают • обуза для пользователей / технический долг • Узко специализированы • применяются за пределами специализации • Недостаточно объяснены • требуют слепого подчинения или эксперта под рукой • Носят запретительный характер Zubkov - Guidelines - C++ Russia 2017 6
  • 7. Набор правил + Библиотека + Статический анализ Чем отличаются Core Guidelines? • Современный С++ (и С++ ближайшего будущего) • Каким вы хотите видеть новый код через пять лет? • Предписания, не запрещения • Плюс разъяснения достаточные для использования в обучении • Не привязаны к конкретной компании • Гитхаб под эгидой isocpp.org • Анализаторы разрабатываются разными компаниями • Центральные (“Core”) • Компании и проекты могут включать и выключать группы правил (“профили”) и дописывать/удалять индивидуальные правила по вкусу – и это уже реальность. Zubkov - Guidelines - C++ Russia 2017 7
  • 8. Набор правил + Библиотека + Статический анализ Чем отличаются Core Guidelines? Не только и не столько стиль программирования, в главные цели входят: • Статическая типобезопасность • Нет возможности обратиться к T как U • Безопасность работы с памятью • Нет доступа за пределы массива • Гарантии времени жизни всех объектов • Нет висячих указателей и ссылок • Ресурсобезопасность • Нет утечек ресурсов, включая утечки памяти • В будущем - больше Zubkov - Guidelines - C++ Russia 2017 8
  • 9. Набор правил + Библиотека + Статический анализ Не цели • не минимальные • не ортогональные • не книга (и не учебник) • не руководство по модернизации кода (хотя есть правила модернизации) • не детальный список особых случаев (для этого есть стандарт) • не подмножество языка (не теряет экспрессивность) • не идеальные (сообщайте об ошибках) Zubkov - Guidelines - C++ Russia 2017 9
  • 10. Набор правил + Библиотека + Статический анализ Правил много! • Не все программисты смогут включить все правила • Как минимум, не сразу: постепенная интеграция жизненно необходима • Многим потребуется больше правил • Для нетипичных ситуаций • Наша цель: центральные правила (Core Guidelines) • Правила для большинства • Переход количества в качество: • Нет утечкам ресурсов • Нет висячим указателям • Нет нарушениям типобезопасности Zubkov - Guidelines - C++ Russia 2017 10
  • 11. Набор правил + Библиотека + Статический анализ “подмножество надмножества” (изначально разработан для доменно-специфичных языков на основе С++) • Нельзя запрещать без альтернатив • Альтернатива – стандартная библиотека • С дополнениями (потому что “прямо сейчас”) Guidelines Support Library (https://github.com/Microsoft/GSL) • Для необычных ситуаций – с собственными дополнениями (MyCompany Support Library) • Авторы библиотеки могут пользоваться грязными/сложными/опасными возможностями языка – для того они и существуют. Цель: безопасная работа с массивами (без дополнительных проверок!) Надмножество (библиотека): std::string_view, gsl::span, gsl::zstring Подмножество (правила): не превращать массивы в указатели не делать арифметику на указателях не передавать указатель и размер Zubkov - Guidelines - C++ Russia 2017 11 C++ GSL Нельзя: Стандартная библиотека Можно:
  • 12. Набор правил + Библиотека + Статический анализ Microsoft Visual Studio LLVM Clang Некоторые другие, близкие по духу, статические анализаторы также планируют включить правила из Code Guidelines (например IFS Cevelop) Zubkov - Guidelines - C++ Russia 2017 12
  • 13. Набор правил + Библиотека + Статический анализ Zubkov - Guidelines - C++ Russia 2017 13 Сколько ошибок в этой программе?
  • 14. Набор правил + Библиотека + Статический анализ Zubkov - Guidelines - C++ Russia 2017 14
  • 15. Набор правил + Библиотека + Статический анализ Zubkov - Guidelines - C++ Russia 2017 15
  • 16. Набор правил + Библиотека + Статический анализ Zubkov - Guidelines - C++ Russia 2017 16
  • 18. github.com/isocpp/CppCoreGuidelines • 2014-2015: Morgan Stanley + Microsoft + ЦЕРН • 13 сентября 2015 (CppCon15): на гитхабе Принимайте участие! Zubkov - Guidelines - C++ Russia 2017 18
  • 19. Цели Core Guidelines • Сделать целые классы ошибок невозможными • Меньше времени в отладчике, меньше шансов для крахов и хаков • Сделать невозможными утечки ресурсов • Без потери производительности • Сделать невозможными висячие указатели • Без потери производительности • Сделать невозможным выход за границы массива • Без потери производительности • Упростить • Простой код проще поддерживать и проще преподавать • Подальше от темных мест и экзотических приемов • Программировать как эксперты Zubkov - Guidelines - C++ Russia 2017 19
  • 20. Секция P: Философия • P.1: Express ideas directly in code • P.2: Write in ISO Standard C++ • P.3: Express intent • P.4: Ideally, a program should be statically type safe • P.5: Prefer compile-time checking to run-time checking • P.6: What cannot be checked at compile time should be checkable at run time • P.7: Catch run-time errors early • P.8: Don't leak any resources • P.9: Don't waste time or space • P.10: Prefer immutable data to mutable data • P.11: Encapsulate messy constructs, rather than spreading through the code Zubkov - Guidelines - C++ Russia 2017 20
  • 21. Секция P: Философия • P.1: Express ideas directly in code • P.2: Write in ISO Standard C++ • P.3: Express intent • P.4: Ideally, a program should be statically type safe • P.5: Prefer compile-time checking to run-time checking • P.6: What cannot be checked at compile time should be checkable at run time • P.7: Catch run-time errors early • P.8: Don't leak any resources • P.9: Don't waste time or space • P.10: Prefer immutable data to mutable data • P.11: Encapsulate messy constructs, rather than spreading through the code Смысл кода должен быть понятен из кода: комментарии не компилируются! change_speed(double s); // Что за double? change_speed(2.3); // В каких единицах? change_speed(Speed s); // ok: это новая скорость change_speed(23_m / 10s); // ok: метры в секунду change_speed(2.3); // ошибка компиляции Zubkov - Guidelines - C++ Russia 2017 21
  • 22. Секция P: Философия • P.1: Express ideas directly in code • P.2: Write in ISO Standard C++ • P.3: Express intent • P.4: Ideally, a program should be statically type safe • P.5: Prefer compile-time checking to run-time checking • P.6: What cannot be checked at compile time should be checkable at run time • P.7: Catch run-time errors early • P.8: Don't leak any resources • P.9: Don't waste time or space • P.10: Prefer immutable data to mutable data • P.11: Encapsulate messy constructs, rather than spreading through the code Пишите на стандартном С++, запрещайте нестандартные расширения языка. Когда они действительно нужны, изолируйте от остального кода. Для gcc и clang “-std=c++14” недостаточно! Расширения отключаются ”-pedantic-errors” Zubkov - Guidelines - C++ Russia 2017 22
  • 23. Секция P: Философия • P.1: Express ideas directly in code • P.2: Write in ISO Standard C++ • P.3: Express intent • P.4: Ideally, a program should be statically type safe • P.5: Prefer compile-time checking to run-time checking • P.6: What cannot be checked at compile time should be checkable at run time • P.7: Catch run-time errors early • P.8: Don't leak any resources • P.9: Don't waste time or space • P.10: Prefer immutable data to mutable data • P.11: Encapsulate messy constructs, rather than spreading through the code Код должен выражать цели, не средства Плохо: int i = 0; while (i < v.size()) { /* работа с v[i] */ } Лучше: for (const auto& x : v) { /* работа с x */ } // порядок важен for_each(par, v, [](int x) { /* работа с x */ }); // порядок неважен Zubkov - Guidelines - C++ Russia 2017 23
  • 24. Секция P: Философия • P.1: Express ideas directly in code • P.2: Write in ISO Standard C++ • P.3: Express intent • P.4: Ideally, a program should be statically type safe • P.5: Prefer compile-time checking to run-time checking • P.6: What cannot be checked at compile time should be checkable at run time • P.7: Catch run-time errors early • P.8: Don't leak any resources • P.9: Don't waste time or space • P.10: Prefer immutable data to mutable data • P.11: Encapsulate messy constructs, rather than spreading through the code Статическая типобезопасность (см также type safety profile) std::variant вместо union Нет преобразований массивов в указатели (см gsl::span) Нет сужающих конверсий (см gsl::narrow_cast) Нет кастов (явных приведений типов) Никаких void* Zubkov - Guidelines - C++ Russia 2017 24
  • 25. Секция P: Философия • P.1: Express ideas directly in code • P.2: Write in ISO Standard C++ • P.3: Express intent • P.4: Ideally, a program should be statically type safe • P.5: Prefer compile-time checking to run-time checking • P.6: What cannot be checked at compile time should be checkable at run time • P.7: Catch run-time errors early • P.8: Don't leak any resources • P.9: Don't waste time or space • P.10: Prefer immutable data to mutable data • P.11: Encapsulate messy constructs, rather than spreading through the code Предпочитайте ошибки компиляции проверкам в коде static_assert(sizeof(void*)==8, “64 bit required”); static_assert(sizeof(VMPage) == PAGESIZE); f(gsl::span<int>); // а не f(int*, int) Zubkov - Guidelines - C++ Russia 2017 25
  • 26. Секция P: Философия • P.1: Express ideas directly in code • P.2: Write in ISO Standard C++ • P.3: Express intent • P.4: Ideally, a program should be statically type safe • P.5: Prefer compile-time checking to run-time checking • P.6: What cannot be checked at compile time should be checkable at run time • P.7: Catch run-time errors early • P.8: Don't leak any resources • P.9: Don't waste time or space • P.10: Prefer immutable data to mutable data • P.11: Encapsulate messy constructs, rather than spreading through the code Если нельзя сделать ошибкой компиляции, должна быть возможность проверить в коде. Контракты (см gsl_assert) Исключения Валидность указателя проверить невозможно!Zubkov - Guidelines - C++ Russia 2017 26
  • 27. Секция P: Философия • P.1: Express ideas directly in code • P.2: Write in ISO Standard C++ • P.3: Express intent • P.4: Ideally, a program should be statically type safe • P.5: Prefer compile-time checking to run-time checking • P.6: What cannot be checked at compile time should be checkable at run time • P.7: Catch run-time errors early • P.8: Don't leak any resources • P.9: Don't waste time or space • P.10: Prefer immutable data to mutable data • P.11: Encapsulate messy constructs, rather than spreading through the code Проверяйте ошибки как можно раньше (идеально в конструкторах, чтобы не повторять проверки) std::vector и gsl::span вместо массивов gsl::not_null вместо указателей Структуры и классы вместо строк Zubkov - Guidelines - C++ Russia 2017 27
  • 28. Секция P: Философия • P.1: Express ideas directly in code • P.2: Write in ISO Standard C++ • P.3: Express intent • P.4: Ideally, a program should be statically type safe • P.5: Prefer compile-time checking to run-time checking • P.6: What cannot be checked at compile time should be checkable at run time • P.7: Catch run-time errors early • P.8: Don't leak any resources • P.9: Don't waste time or space • P.10: Prefer immutable data to mutable data • P.11: Encapsulate messy constructs, rather than spreading through the code Никаких утечек ресурсов – памяти, файлов, и т п. RAII классы (std::vector, std::fstream, std::lock_guard) std::make_unique/std::make_shared gsl::finally Никаких malloc/free/new/delete/strdup/fopen Zubkov - Guidelines - C++ Russia 2017 28
  • 29. Секция P: Философия • P.1: Express ideas directly in code • P.2: Write in ISO Standard C++ • P.3: Express intent • P.4: Ideally, a program should be statically type safe • P.5: Prefer compile-time checking to run-time checking • P.6: What cannot be checked at compile time should be checkable at run time • P.7: Catch run-time errors early • P.8: Don't leak any resources • P.9: Don't waste time or space • P.10: Prefer immutable data to mutable data • P.11: Encapsulate messy constructs, rather than spreading through the code Эффективно используйте и память и процессор: это все-таки C++! Всегда планируйте как минимум возможность оптимизации (Per.7). Избегайте лишнего кода (знайте, что есть в библиотеках), лишних проверок (см P.7 и правила об инвариантах), избыточные структуры данных (от ненужных связных списков до плохо упакованных структур). Zubkov - Guidelines - C++ Russia 2017 29
  • 30. Секция P: Философия • P.1: Express ideas directly in code • P.2: Write in ISO Standard C++ • P.3: Express intent • P.4: Ideally, a program should be statically type safe • P.5: Prefer compile-time checking to run-time checking • P.6: What cannot be checked at compile time should be checkable at run time • P.7: Catch run-time errors early • P.8: Don't leak any resources • P.9: Don't waste time or space • P.10: Prefer immutable data to mutable data • P.11: Encapsulate messy constructs, rather than spreading through the code Предпочитайте константы и неизменяемые данные Все что может быть constexpr или const, должно быть: объекты, методы, ссылки и указатели. (исключения – объекты, возвращаемые из функций) Zubkov - Guidelines - C++ Russia 2017 30
  • 31. Секция P: Философия • P.1: Express ideas directly in code • P.2: Write in ISO Standard C++ • P.3: Express intent • P.4: Ideally, a program should be statically type safe • P.5: Prefer compile-time checking to run-time checking • P.6: What cannot be checked at compile time should be checkable at run time • P.7: Catch run-time errors early • P.8: Don't leak any resources • P.9: Don't waste time or space • P.10: Prefer immutable data to mutable data • P.11: Encapsulate messy constructs, rather than spreading through the code Прячьте грязный код в библиотеках за удобными интерфейсами, и больше им не пользуйтесь. Это опять принцип “подмножество надмножества” в стандартной библиотеке масса примеров: union внутри std::variant, указатели внутри std::vector и пр Zubkov - Guidelines - C++ Russia 2017 31
  • 32. Интерфейсы (фрагмент) • I.1: Make interfaces explicit • I.2: Avoid global variables • I.3: Avoid singletons • I.4: Make interfaces precisely and strongly typed • I.5: State preconditions (if any) • I.7: State postconditions • I.10: Use exceptions to signal a failure to perform a required task • I.11: Never transfer ownership by a raw pointer (T*) • I.12: Declare a pointer that must not be null as not_null • I.13: Do not pass an array as a single pointer • I.24: Avoid adjacent unrelated parameters of the same type • I.26: If you want a cross-compiler ABI, use a C-style subset Zubkov - Guidelines - C++ Russia 2017 32
  • 33. Интерфейсы (фрагмент) • I.1: Make interfaces explicit • I.2: Avoid global variables • I.3: Avoid singletons • I.4: Make interfaces precisely and strongly typed • I.5: State preconditions (if any) • I.7: State postconditions • I.10: Use exceptions to signal a failure to perform a required task • I.11: Never transfer ownership by a raw pointer (T*) • I.12: Declare a pointer that must not be null as not_null • I.13: Do not pass an array as a single pointer • I.24: Avoid adjacent unrelated parameters of the same type • I.26: If you want a cross-compiler ABI, use a C-style subset Zubkov - Guidelines - C++ Russia 2017 33 Передача массива в виде одного указателя и даже в виде пары аргументов (указатель и размер, указатели на начало и конец) – источник ошибок. Размер массива не должен быть отделен от самого массива. Плохо: void copy_n(const T* p, T* q, int n); // копия из [p:p+n) в [q:q+n) Лучше: void copy(gsl::span<const T> r, gsl::span<T> r2); // копия из r в r2
  • 34. Интерфейсы (фрагмент) • I.1: Make interfaces explicit • I.2: Avoid global variables • I.3: Avoid singletons • I.4: Make interfaces precisely and strongly typed • I.5: State preconditions (if any) • I.7: State postconditions • I.10: Use exceptions to signal a failure to perform a required task • I.11: Never transfer ownership by a raw pointer (T*) • I.12: Declare a pointer that must not be null as not_null • I.13: Do not pass an array as a single pointer • I.24: Avoid adjacent unrelated parameters of the same type • I.26: If you want a cross-compiler ABI, use a C-style subset Zubkov - Guidelines - C++ Russia 2017 34 Функции сообщают от ошибках исключениями (“ошибка” – невозможность выполнить свою функцию, гарантировать постусловие или восстановить инвариант). int printf(const char* ...); // Плохо: возвращает код ошибки template <class F, class ...Args> explicit thread(F&& f, Args&&... args); // Лучше: бросает system_error
  • 35. Функции (фрагмент) Zubkov - Guidelines - C++ Russia 2017 35 • F.22: Use T* or owner<T*> or a smart pointer to designate a single object • F.23: Use a not_null<T> to indicate "null" is not a valid value • F.24: Use a span<T> or a span_p<T> to designate a half-open sequence • F.25: Use a zstring or a not_null<zstring> to designate a C-style string • F.26: Use a unique_ptr<T> to transfer ownership where a pointer is needed • F.27: Use a shared_ptr<T> to share ownership • F.44: Return a T& when copy is undesirable and "returning no object" isn't an option • F.45: Don't return a T&& • F.50: Use a lambda when a function won't do (to capture local variables, or to write a local function) • F.51: Where there is a choice, prefer default arguments over overloading • F.52: Prefer capturing by reference in lambdas that will be used locally
  • 36. Функции (фрагмент) Zubkov - Guidelines - C++ Russia 2017 36 • F.22: Use T* or owner<T*> or a smart pointer to designate a single object • F.23: Use a not_null<T> to indicate "null" is not a valid value • F.24: Use a span<T> or a span_p<T> to designate a half-open sequence • F.25: Use a zstring or a not_null<zstring> to designate a C-style string • F.26: Use a unique_ptr<T> to transfer ownership where a pointer is needed • F.27: Use a shared_ptr<T> to share ownership • F.44: Return a T& when copy is undesirable and "returning no object" isn't an option • F.45: Don't return a T&& • F.50: Use a lambda when a function won't do (to capture local variables, or to write a local function) • F.51: Where there is a choice, prefer default arguments over overloading • F.52: Prefer capturing by reference in lambdas that will be used locally • gsl::not_null<T> (где T = U*, std::unique_ptr<U>, std::shared_ptr<U>), гарантирует что T - не нулевой указатель. (см также I.12) • Если параметр not_null, проверка в вызываемой функции не нужна • Eсли результат not_null, проверка в вызывающей функции не нужна int f(const int* p, gsl::not_null<const int*> q) { if(q) return *q; // бессмысленная проверка (F.23) return *p; // опасный код! Голый указатель может быть нулевым (F.60) }
  • 37. Функции (фрагмент) Zubkov - Guidelines - C++ Russia 2017 37 • F.22: Use T* or owner<T*> or a smart pointer to designate a single object • F.23: Use a not_null<T> to indicate "null" is not a valid value • F.24: Use a span<T> or a span_p<T> to designate a half-open sequence • F.25: Use a zstring or a not_null<zstring> to designate a C-style string • F.26: Use a unique_ptr<T> to transfer ownership where a pointer is needed • F.27: Use a shared_ptr<T> to share ownership • F.44: Return a T& when copy is undesirable and "returning no object" isn't an option • F.45: Don't return a T&& • F.50: Use a lambda when a function won't do (to capture local variables, or to write a local function) • F.51: Where there is a choice, prefer default arguments over overloading • F.52: Prefer capturing by reference in lambdas that will be used locally • Если есть возможность, пользуйтеся аргументами по умолчанию вместо перегрузки функций: перегрузка – для похожих операций над аргументами разных типов. • Плохо: нет гарантии что код этих двух функций идентичен void print(const string& s); // формат по умолчанию void print(const string& s, format f); • Лучше: void print(const string& s, format f = {});
  • 38. Параметры и аргументы (фрагмент) Zubkov - Guidelines - C++ Russia 2017 38
  • 39. Классы (фрагмент) Zubkov - Guidelines - C++ Russia 2017 39 • C.2: Use class if the class has an invariant; use struct if the data members can vary independently • C.4: Make a function a member only if it needs direct access to the representation of a class • C.5: Place helper functions in the same namespace as the class they support • C.20: If you can avoid defining any default operations, do • C.21: If you define or =delete any default operation, define or =delete them all • C.35: A base class with a virtual function needs a virtual destructor • C.36: A destructor may not fail • C.40: Define a constructor if a class has an invariant • C.41: A constructor should create a fully initialized object • C.42: If a constructor cannot construct a valid object, throw an exception • C.43: Ensure that a class has a default constructor • C.45: Prefer to use member initializers
  • 40. Классы (фрагмент) Zubkov - Guidelines - C++ Russia 2017 40 • C.2: Use class if the class has an invariant; use struct if the data members can vary independently • C.4: Make a function a member only if it needs direct access to the representation of a class • C.5: Place helper functions in the same namespace as the class they support • C.20: If you can avoid defining any default operations, do • C.21: If you define or =delete any default operation, define or =delete them all • C.35: A base class with a virtual function needs a virtual destructor • C.36: A destructor may not fail • C.40: Define a constructor if a class has an invariant • C.41: A constructor should create a fully initialized object • C.42: If a constructor cannot construct a valid object, throw an exception • C.43: Ensure that a class has a default constructor • C.45: Prefer to use member initializers • Конструктор устанавливает инвариант, функции-члены считают, что инвариант гарантирован. • Если данные можно менять напрямую, инвариант невозможен. • struct Desc { string left; // left и right могут меняться независимо друг от друга string right; // инварианта нет }; • class IntArray { public: // конструкторы, деструктор и пр private: gsl::owner<int*> beg; // инвариант: beg указывает на массив int* end; // инвариант: end указывает на конец массива };
  • 41. Классы (фрагмент) Zubkov - Guidelines - C++ Russia 2017 41 • C.2: Use class if the class has an invariant; use struct if the data members can vary independently • C.4: Make a function a member only if it needs direct access to the representation of a class • C.5: Place helper functions in the same namespace as the class they support • C.20: If you can avoid defining any default operations, do • C.21: If you define or =delete any default operation, define or =delete them all • C.35: A base class with a virtual function needs a virtual destructor • C.36: A destructor may not fail • C.40: Define a constructor if a class has an invariant • C.41: A constructor should create a fully initialized object • C.42: If a constructor cannot construct a valid object, throw an exception • C.43: Ensure that a class has a default constructor • C.45: Prefer to use member initializers • Стандартные конструкторы • Делают возможным массивы и упрощают код • Требуются для все регулярных типов • Предоставляют состояние, которое можно использовать в операциях перемещения • class Date { public: Date(Day dd, Month mm, Year yyyy); Date() = default; // См C.45 private: int day = 1; int month = 1; int year = 1970; }; std::vector<Date> vd(1000);
  • 42. Наследование (фрагмент) • C.121: If a base class is used as an interface, make it a pure abstract class • C.126: An abstract class typically doesn't need a constructor • C.127: A class with a virtual function should have a virtual or protected destructor • C.128: Virtual functions should specify exactly one of virtual, override, or final • C.131: Avoid trivial getters and setters • C.132: Don't make a function virtual without reason • C.133: Avoid protected data • C.138: Create an overload set for a derived class and its bases with using • C.140: Do not provide different default arguments for a virtual function and an overrider • C.146: Use dynamic_cast where class hierarchy navigation is unavoidable • C.147: Use dynamic_cast to a reference type when failure to find the required class is considered an error • C.152: Never assign a pointer to an array of derived class objects to a pointer to its base Zubkov - Guidelines - C++ Russia 2017 42
  • 43. Наследование (фрагмент) • C.121: If a base class is used as an interface, make it a pure abstract class • C.126: An abstract class typically doesn't need a constructor • C.127: A class with a virtual function should have a virtual or protected destructor • C.128: Virtual functions should specify exactly one of virtual, override, or final • C.131: Avoid trivial getters and setters • C.132: Don't make a function virtual without reason • C.133: Avoid protected data • C.138: Create an overload set for a derived class and its bases with using • C.140: Do not provide different default arguments for a virtual function and an overrider • C.146: Use dynamic_cast where class hierarchy navigation is unavoidable • C.147: Use dynamic_cast to a reference type when failure to find the required class is considered an error • C.152: Never assign a pointer to an array of derived class objects to a pointer to its base Zubkov - Guidelines - C++ Russia 2017 43 • Если в классе есть виртуальная функция, деструктор должет быть виртуальными и доступным или невиртуальным и защищенным • (удаление полиморфного класса с невиртуальным деструктором через базовый указатель – неопределенное поведение) • struct B { virtual int f() = 0; // деструктор по умолчанию доступный и невиртуальный }; struct D : B { string s {"default"}; }; void use() { std::unique_ptr<B> p = std::make_unique<D>(); } // Undefined Behavior (как минимум утечка памяти из-за строки)
  • 44. Наследование (фрагмент) • C.121: If a base class is used as an interface, make it a pure abstract class • C.126: An abstract class typically doesn't need a constructor • C.127: A class with a virtual function should have a virtual or protected destructor • C.128: Virtual functions should specify exactly one of virtual, override, or final • C.131: Avoid trivial getters and setters • C.132: Don't make a function virtual without reason • C.133: Avoid protected data • C.138: Create an overload set for a derived class and its bases with using • C.140: Do not provide different default arguments for a virtual function and an overrider • C.146: Use dynamic_cast where class hierarchy navigation is unavoidable • C.147: Use dynamic_cast to a reference type when failure to find the required class is considered an error • C.152: Never assign a pointer to an array of derived class objects to a pointer to its base Zubkov - Guidelines - C++ Russia 2017 44 • Тривиальные геттеры и сеттеры не нужны • // Плохо: • class Point { int x; public: int get_x() const { return x; } void set_x(int xx) { x = xx; } }; • // Лучше • struct Point { int x = 0; }
  • 45. Шаблоны (фрагмент) • T.5: Combine generic and OO techniques to amplify their strengths, not their costs • T.61+T.62: Don’t over-parametrize • T.64: Use specialization to provide alternative implementations of class templates • T.65: Use tag dispatch to provide alternative implementations of functions • T.67: Use specialization to provide alternative implementations for irregular types • T.69: Inside a template, don't make an unqualified nonmember function call unless you intend it to be a customization point • #749 avoid recursion in variadic templates • T.122: Use templates (usually template aliases) to compute types at compile time • T.123: Use constexpr functions to compute values at compile time • T.144: Don't specialize function templates Zubkov - Guidelines - C++ Russia 2017 45
  • 46. Шаблоны (фрагмент) • T.5: Combine generic and OO techniques to amplify their strengths, not their costs • T.61+T.62: Don’t over-parametrize • T.64: Use specialization to provide alternative implementations of class templates • T.65: Use tag dispatch to provide alternative implementations of functions • T.67: Use specialization to provide alternative implementations for irregular types • T.69: Inside a template, don't make an unqualified nonmember function call unless you intend it to be a customization point • #749 avoid recursion in variadic templates • T.122: Use templates (usually template aliases) to compute types at compile time • T.123: Use constexpr functions to compute values at compile time • T.144: Don't specialize function templates Zubkov - Guidelines - C++ Russia 2017 46 • Излишняя параметризация – источник раздувания кода (даже если компилятор поддерживает ICF). • Если член шаблона зависит только от N параметров, он должен быть в базовом классе, зависящем только от этих N параметров. • // Плохо: • template<typename T> class Foo { enum { v1, v2 }; … }; • // Лучше: • struct Foo_base { enum { v1, v2 }; … }; template<typename T> class Foo : public Foo_base { … };
  • 47. Шаблоны (фрагмент) • T.5: Combine generic and OO techniques to amplify their strengths, not their costs • T.61+T.62: Don’t over-parametrize • T.64: Use specialization to provide alternative implementations of class templates • T.65: Use tag dispatch to provide alternative implementations of functions • T.67: Use specialization to provide alternative implementations for irregular types • T.69: Inside a template, don't make an unqualified nonmember function call unless you intend it to be a customization point • #749 avoid recursion in variadic templates • T.122: Use templates (usually template aliases) to compute types at compile time • T.123: Use constexpr functions to compute values at compile time • T.144: Don't specialize function templates Zubkov - Guidelines - C++ Russia 2017 47 • Рекурсия в шаблонном коде тормозит компиляцию. Ее можно избежать при помощи fold expressions, constexpr функций, std::index_sequence (std::invoke и т п) и просто pack expansions. • // Плохо: • template<class T> void pbv(vector<T>& v) {} template<class T, class H, class... Ts> void pbv(vector<T>& v, H&& h, Ts&&... Ts) { v.push_back(h); pbv(v, ts...); } • // Лучше template<class T, class... Ts) void pbv(vector<T>& v, Ts&&... Ts) { (v.push_back(ts), ...); }
  • 48. Профили • Профиль – набор правил ставящих целью обеспечить конкретную гарантию. • Type safety (типобезопасность) • Bounds safety (безопасность работы с массивами) • Lifetime safety (гарантии времени жизни объектов) • В будущем – arithmetic, concurrency, noexcept, noalloc, etc. Zubkov - Guidelines - C++ Russia 2017 48
  • 49. Профиль типобезопасности • P.4: Ideally, a program should be statically type safe • C.183: Don't use a union for type punning • Type.1: Don't use reinterpret_cast • Type.2: Don't use static_cast downcasts. Use dynamic_cast instead • Type.3: Don't use const_cast to cast away const (i.e., at all) • Type.4: Don't use C-style (T)expression casts that would perform a static_cast downcast, const_cast, or reinterpret_cast • Type.5: Don't use a variable before it has been initialized • Type.6: Always initialize a member variable Zubkov - Guidelines - C++ Russia 2017 49
  • 50. Массивы и Указатели (Bounds Profile) • ES.55: Avoid the need for range checking • Bounds.1: Don't use pointer arithmetic. Use span instead. • Bounds.2: Only index into arrays using constant expressions. • Bounds.3: No array-to-pointer decay. • Bounds.4: Don't use standard library functions and types that are not bounds-checked. Zubkov - Guidelines - C++ Russia 2017 50
  • 51. Контроль времени жизни объектов (Lifetime Profile) 1. У каждого объекта есть только один владелец 2. На объект могут ссылаться много ссылок/указателей 3. Никакая ссылка/указатель не может пережить владельца • Правила для обычной функции: • Не показывать ссылку/указатель на локальную переменную тому кто вызвал • Ссылка/указатель переданная как аргумент может быть возвращена • Указатель от new может быть возвращен если мы сообщим что этот указатель – владелец int* f(int* p) { int x = 4; return &x; // Ошибка return new int{7}; // OK, только надо отметить что это - владелец return p; // OK: откуда пришло, туда и вернется } Zubkov - Guidelines - C++ Russia 2017 51
  • 52. Контроль времени жизни объектов (Lifetime Profile) • Как отмечать владельцев? • Предпочтительно: std::unique_ptr, std::vector, std::map, std::shared_ptr, • На низком уровне (например внутри std::vector<T>): gsl::owner<T> template<class T> using owner = T; • Этот низкоуровневый owner существует только на уровне системы типов и статического анализа, в компилированном коде он неотличим от T vector<int*> f(int* p) { owner<int*> q = new int{7}; vector<int*> res = {p, q}; // OK: копия q – не владелец return res; // Ошибка: владелец должен быть возвращен или удален } Zubkov - Guidelines - C++ Russia 2017 52
  • 53. Правила будущего • T.10/I.9: Specify concepts for all template arguments • T.11: Whenever possible use standard concepts • T.12: Prefer concept names over auto for local variables • T.13: Prefer the shorthand notation for simple, single-type argument concepts • T.20: Avoid "concepts" without meaningful semantics • T.21: Require a complete set of operations for a concept • T.22: Specify axioms for concepts • T.23: Differentiate a refined concept from its more general case by adding new use patterns • T.24: Use tag classes or traits to differentiate concepts that differ only in semantics • T.25: Avoid complementary constraints • T.26: Prefer to define concepts in terms of use-patterns rather than simple syntax • T.30+31: Use !C<T> / C1<T> || C2<T> sparingly • I.6+8: Prefer Expects() for expressing preconditions/ Ensures() for expressing postconditions Zubkov - Guidelines - C++ Russia 2017 53 См также http://stroustrup.com/good_concepts.pdf
  • 54. Не-правила и мифы • NR.1: Don't: All declarations should be at the top of a function • NR.2: Don't: Have only a single return-statement in a function • NR.3: Don't: Don't use exceptions • NR.4: Don't: Place each class declaration in its own source file • NR.5: Don't: Don't do substantive work in a constructor; instead use two-phase initialization • NR.6: Don't: Place all cleanup actions at the end of a function and goto exit • NR.7: Don't: Make all data members protected Zubkov - Guidelines - C++ Russia 2017 54
  • 55. Слишком много правил? • Эти правила для всех: • Новичков, экспертов, библиотек, системщиков, обычных и необычных приложений • Никто не предлагает выучить все эти правила! • Никто не предлагает даже прочитать все эти правила! • Подавляющее большинство правил предназначено для анализаторов: • Анализ отметит возможное нарушение и покажет какое правило прочитать: • Zubkov - Guidelines - C++ Russia 2017 55
  • 56. Мы хотим хороший современный С++ • “Мы” значит “вы” • это не под силу одному человеку или одной компании • Каким вы хотите видеть код через 5 лет? • “Таким же как и сегодня” – не ответ • Модернизировать много кода – нелегко • Если ясна цель – можно к ней двигаться • Не все согласны с тем как выглядит хороший С++ • Код не должен выглядеть одинакого • Но должно быть общее ядро • Нужно обсуждать и применять правила и анализаторы • Помогайте! • Нужны правила, анализ, комментарии, редакторы https://github.com/isocpp/CppCoreGuidelines Zubkov - Guidelines - C++ Russia 2017 56
  • 57. Zubkov - Guidelines - C++ Russia 2017 57
  • 58. extras Zubkov - Guidelines - C++ Russia 2017 58
  • 59. Обработка ошибок (фрагмент) • E.1: Develop an error-handling strategy early in a design • E.2: Throw an exception to signal that a function can't perform its assigned task • E.3: Use exceptions for error handling only • E.5: Let a constructor establish an invariant, and throw if it cannot • E.12: Use noexcept when exiting a function because of a throw is impossible or unacceptable • E.13: Never throw while being the direct owner of an object • E.14: Use purpose-designed user-defined types as exceptions (not built-in types) • E.15: Catch exceptions from a hierarchy by reference • E.16: Destructors, deallocation, and swap must never fail • E.17: Don't try to catch every exception in every function • E.18: Minimize the use of explicit try/catch • E.19: Use a final_action object to express cleanup if no suitable resource handle is available Zubkov - Guidelines - C++ Russia 2017 59
  • 60. Многозадачность (избранное) • CP.4: Think in terms of tasks, rather than threads • CP.8: Don't try to use volatile for synchronization • CP.20+21: Use RAII, never plain lock()/unlock() / Use std::lock() to acquire multiple mutexes • CP.22: Never call unknown code while holding a lock (e.g., a callback) • CP.23+24: Think of a joining thread as a scoped container / a detached thread as a global container • CP.25+26: Prefer gsl::raii_thread / gsl::detached_thread • CP.31: Pass small amounts of data between threads by value, rather than by reference or pointer • CP.32: To share ownership between unrelated threads use shared_ptr • CP.42: Don't wait without a condition • CP.50: Define a mutex together with the data it protects • Use algorithms that are designed for parallelism, not algorithms with unnecessary dependency on linear evaluation • CP.60: Use a future to return a value from a concurrent task • CP.100: Don't use lock-free programming unless you absolutely have to Zubkov - Guidelines - C++ Russia 2017 60
  • 61. Управление ресурсами • R.1: Manage resources automatically using resource handles and RAII • R.3: A raw pointer (a T*) is non-owning • R.4: A raw reference (a T&) is non-owning • R.5: Prefer scoped objects • R.10+11: Avoid malloc() and free() / Avoid calling new and delete explicitly • R.12: Immediately give the result of an explicit resource allocation to a manager object • R.13: Perform at most one explicit resource allocation in a single expression statement • R.15: Always overload matched allocation/deallocation pairs • R.20: Use unique_ptr or shared_ptr to represent ownership • R.21: Prefer unique_ptr over shared_ptr unless you need to share ownership • R.22+23: Use make_shared() to make shared_ptrs / make_unique() to make unique_ptrs • R.30: Take smart pointers as parameters only to explicitly express lifetime semantics Zubkov - Guidelines - C++ Russia 2017 61
  • 62. Выражения и инструкции (избранное) • ES.5: Keep scopes small • ES.11: Use auto to avoid redundant repetition of type names • ES.20: Always initialize an object • ES.21+22: Don't introduce a variable (or constant) before you need to use it / until you have a value to initialize it with • ES.23: Prefer the {}-initializer syntax • ES.24: Use a unique_ptr<T> to hold pointers in code that may throw • ES.26: Don't use a variable for two unrelated purposes • ES.28: Use lambdas for complex initialization, especially of const variables • ES.30+31: Don't use macros for program text manipulation / for constants or "functions" • ES.45: Avoid narrowing conversions • ES.48: Avoid casts • ES.56: Avoid std::move() in application code • ES.63: Don't slice Zubkov - Guidelines - C++ Russia 2017 62
  • 63. const • P.10: Prefer immutable data to mutable data • ES.25: Declare an object const or constexpr unless you want to modify its value later on • ES.50: Don't cast away const • F.4: If a function may have to be evaluated at compile time, declare it constexpr • R.6: Avoid non-const global variables • Con.1: By default, make objects immutable • Con.2: By default, make member functions const • Con.3: By default, pass pointers and references to consts • Con.4: Use const to define objects with values that do not change after construction • Con.5: Use constexpr for values that can be computed at compile time Zubkov - Guidelines - C++ Russia 2017 63

Editor's Notes

  • #2: Бьярне приехал бы сам, но завтра он летит на заседание комитета
  • #3: Если кто не знает что это такое – вы мало сидите в Интернете! главная тема CppConа в сентябре 2015го года
  • #4: В этой формулировке ответ тривиален:11, 14, 17 + libfun, fs, par, tm, concepts + ranges v3, hana, metaparse
  • #5: * справедливости ради стоит заметить укромных уголков стало больше, несмотря на то что сам язык стал проще * любимый анекдот Страуструпа
  • #6: изменения в стандарт –результат за 3 года при удачном стечении обстоятельств практика не на стороне языков которые пытаются заменить с++ если провести черту и сказать вот – новое а вот старое – будет как с Питоном
  • #7: “не делайте это” – те кому это необходимо скажут что правила не для них
  • #8: Не запрещать – задавать направление
  • #9: Гайдлайны – не о том где ставить скобочки – мы замахнулись на намного более серьезные темы висячие ссылки – помните что Раст встревожился? Это только начало
  • #10: – если нужен учебник, вы знаете где его взять – это правила будущего – не были отполированы до блеска перед тем как мы их выложили на гитхаб – целые секции были в зачаточном состоянии
  • #11: нетипичные ситуации: если нет динамической памяти или жесткое реальное время или фреймворк
  • #12: - Возможности, использовние которые сопряжено с риском можно поместить в библиотеку за безопасным удобным интерфейсом - Чтобы действительно достичь безопасности, у правил должны быть зубы
  • #13: Микрософт впереди но я надеюсь чо гуглу будет стыдно и он догонит и перегонит
  • #15: Квадратные скобки – это арифметика на указателе
  • #19: - вернувшись из профессуры в программирование бьярне увидел своими глазами как программисты воспринимают современный с++ - Вклад из финансов, програмного обеспечения, и науки
  • #20: Для простых задач код должен быь простым
  • #21: Хотя цель правил - статический анализ, некоторые правила не поддаются анализу.
  • #22: Пример - библиотека Ховарда Хиннанта для календарного времени
  • #23: Прятать в библиотеку = ту самую myCompanySL
  • #24: Индекс, квадратные скобки, явный размер – все это средства достижения цели
  • #25: Полное стирание информации о типе – это самое ужасное нарушение типобезопасность какое только можно придумать
  • #26: Есть такая тенденция, особенно среди сишников “давай скорее дописывай код чтобы начать его отлаживать” Многие проводят всю жизнь в отладчике Это – не программирование. Ошибка компиляции – это счастье
  • #27: Сюда входят аспекты дизайна для тестирования Компромисс по контрактам был достигнут, но слишком поздно
  • #28: функции не знают что указатель не может быть нулевым если эта информация не была передана как часть типа В финансовом мире такие классы очень популярны
  • #29: Выделение ресурса это инициализация пользоваться ими нельзя – кроме как во внутренних деталях RAII класса
  • #30: Дональд Кнут конечно гений, но… Хороший дизайн можно улучшить в будущем - рост проекта - производительность
  • #31: корректность проверяемая на этапе компиляции возможность оптимизации безопасная многозадачность Возврат из функций – особенность с++11
  • #32: - прячем указатели в умных указателях, прячем мутексы в локах Эти 11 припципов не проверяемые – это направления
  • #33: Фрагмент потому что правил много
  • #34: Кто то вызовет это не с тем размером и запустится код который хитрый хакер прописал куда надо
  • #35: Конструкторы, оператор + для строк Кто проверяет результат printf?
  • #38: Аргумент против – на аргументы по умолчанию есть ограничения (на это тоже есть гайдлайн)
  • #39: Если функция возвращает объект – она должна возвращать объект а не ссылку или указатель Если функция изменяет объект – он передается по ссылка а не как указатель
  • #41: Многие вводят дополнительные значения для классов заданных struct и class
  • #42: Для примера здесь приведена дата – тип у которого нет естественного пустого состояния – мы выбирает одно из возможных состояний как стандартное
  • #45: Допустим есть объект кирпич и у него есть поле вес. Или банковский счет (реальный счет конечно не хранит баланс как поле класса)
  • #47: ICF требует gold linker, COMDAT folding включен по умолчанию +SCARY итераторы как пример
  • #48: И с каждой новой ревизией языка возможностей избежать рекурсию становится больше
  • #49: Если рассказывать о каждом правиле в отдельности, мы тут просидим целый день Пользователи могут включать и выключать отдельные правила но некоторые правила в совокупности – большее чем сумма частей
  • #50: Все это и некоторые другие правила в совокупности гарантируют что к одному типу нельзя обратиться как к другому
  • #51: (range check) Либо на этапе компиляции либо интервальй цикл
  • #52: Помните что волнуется Раст?
  • #54: Концепции – это предикаты над типами, долгожданные интерфейсы для шаблонов Смысл концепции должен быть больше чем простой совокупностью ограничений
  • #55: популярные и ошибочные мифы
  • #56: Наш подход атака с трех сторон – правила + библиотека + анализ. Два без третьего не работают
  • #57: Мы – не Страуструп и ко, “мы” – программисты если мы понимаем в каком направлении двигаться, мы можем начать движение прямо сейчас У разных индустрий и разных ситуаций есть разные требования, но общее ядро И поэтому мы обращаемся к вам за помощью – поэтому эти правила и были выложены в сыром виде – мы хотим услышать от программистов изо всех ситуаций, во всём мире.
  • #60: Если будет вопрос про исключения
  • #61: Если будет вопрос про многозадачность