C++ 1MIT весна 1 2020 — различия между версиями
Ahuletsk (обсуждение | вклад) (→Практика 4: Гулецкий) |
Ahuletsk (обсуждение | вклад) (→Практика 4: Гулецкий) |
||
Строка 205: | Строка 205: | ||
Префикс в теме письма: <code>[C++TA]</code> | Префикс в теме письма: <code>[C++TA]</code> | ||
+ | |||
+ | Trac: <code>huletski</code> | ||
[https://github.com/evlinsky/cpp/tree/master/ta/huletski/HSE_S20 Код с практик] | [https://github.com/evlinsky/cpp/tree/master/ta/huletski/HSE_S20 Код с практик] |
Версия 11:20, 16 января 2020
Содержание
Лекции
Лектор: Суворов Егор Федорович (egor_suvorov@mail.ru)
Весенний семестр
Планы лекций Егора: github.com/yeputons/hse-2019-cpp
Прочие материалы
Ссылки:
- Инструкцией по установке виртуальной машины с Linux
- Про стиль (coding convention)
- Про linux (на русском: Файл:Linux-intro-rus.pdf)
- Ликбез по C++
- Ликбез по svn
- Про зарезервированные имена в Си и C++: stackoverflow.com/a/228797/767632
- Морально устаревшая версия курса в формате видео лекций.
- Студенческие конспекты этого и идеологически близких курсов: cpp1 cpp2 cpp3
Книги:
- Язык C++
- Б. Страуструп, Язык программирования С++
- Б. Эккель, Философия C++
- Дополнительно
- Б. Страуструп, Дизайн и эволюция языка C++
- С. Майерс, Эффективное использование С++/Эффективное использование STL
- Г. Сеттер, Решение сложных задач на C++/Новые сложные задачи на C++
- Р. Седжвик, Алгоритмы на C++
Осенний семестр
Презентации первого семестра Евгения Линского (I поток):
- Лекция 2. Указатели.
- Лекция 3. Три вида памятив С/C++.
- Лекция 4. Структуры. Указатели на функцию. Разное.
- Лекция 5. const в C. Обзор libc: stdio.
- Лекция 6. Обзор libc. С++: ссылки, new, delete. Введение в ООП.
- Лекция 7. ООП: инкапсуляция.
- Лекция 8. const, mutable, static, inline.
- Лекция 9. Перегрузка операторов.
- Лекция 10. Объекты и new/delete. Умные указатели. Наследование.
- Лекция 11. Полиморфизм.
- Лекция 12. Наследование: разное. C++11: разное.
Планы лекций Егора (II поток): github.com/yeputons/hse-2019-cpp
Презентации ликбеза по С:
- Лекция 1. Переменные. Арифмитические выражения.
- Лекция 2. Логические выражение. Управляющие конструкции.
- Лекция 3. Логические операторы. Массивы. Стркои.
Оценка за курс
Лабораторные и домашние
Практика 1: Соколов
Преподаватель: Вячеслав Соколов (vi.soksok@gmail.com, +7 921 780 11 12)
Trac: sokolov
Письма просьба идентифицировать префиксом в теме [HSE][CPP]
Linux
- Текстовые редакторы
subl
Sublime textcode
Visual Studio Code
- Исследование бинарных артефактов
nm
list symbols from object filesreadelf
displays information about ELF filesc++filt
demangle symbols
Ограничение процесса по ресурсам в Linux
- Рекомендуется использовать systemd-run:
systemd-run --scope -p MemoryLimit=2M -p MemoryAccounting=yes ./a.out
. В этом примере ограничивается память 2 мебибайтами.
Дальнеший текст - для тех, кто хочет более глубокого погружения.
- Подробная статья с разбором разных аспектов. Понимать ее полностью не нужно, разбор достаточно подробный и из-за этого может быть непонятен.
Краткий перечень ключевых слов и какие есть проблемы при использовании:
- cgroups - можно просто взять и использовать, но придется повозиться, не очень удобно. Требует понимания, как что устроено, соответственно и времени потребует.
- ulimit - много разных версий, от конкретного shell-а зависит как пример использования, так и доступная функциональность. Легко может не сработать.
- Использование LD_PRELOAD и собственного аллокатора памяти. У меня аллокатор libmemrestrict.so по ссылке из статьи крашится с SEGFAULT, возможно, это я где-то напортачил. Если захотите идти этим путем - спрашивайте меня, есть несколько нетрививальных моментов.
- docker - популярный способ работы с контейнерами
Для тех, кому хочется поэкспериментировать с консолью
- Эмуляторы терминала
- terminator
- tilix
- а также много других, легко ищутся
- Shell
Системы сборки
Для наших нужд достаточно Make
Если проект становится большим, нужно что-то посложнее, например (альтернативы):
Полезные сайты
- godbolt - compiler explorer (удобно делиться примерами)
- ideone - возможность делиться кодом, поддержка разных ЯП, исполнение кода online
- stackoverflow - огромное количество ответов на разные вопросы. Прежде чем самому задавать вопрос, будет полезно ознакомиться с текстом https://habr.com/ru/post/339038/
- [1] - список библиотек из 1-2 файлов
- [2] - список open-source библиотек на языке Си++
- [3] - история языка Си++
Статьи
- UB в языке C++
- integer overflow proposal - предложение в Стандарт языка C++: integer overflow - не UB.
- another integer overflow proposal - ну хотя бы Unspecified Behaviour, лишь бы не UB! (наболело)
- попытка решить проблему UB в языке C++
- обсуждение про выравнивание
- Антипаттерны
- Почему важно проверять, что вернула функция malloc
Практика
16.01.20
- https://godbolt.org/z/Qgdzxv
- https://godbolt.org/z/qWPHdR
- https://godbolt.org/z/rXic4J
- https://godbolt.org/z/qyWCQl
Требования корректности, предъявляемые к работам
1. Проверка контрактов функций.
На мой взгляд, чуть ли не единственной обязательной к использованию парадигмой и доступной во всех языках программирования, выше ассемблера, является [4]. Ключевые понятия: предусловия, постусловия и инварианты. В языках C/C++ соблюдение контрактов контролируется с помощью assert, возведения сигналов, бросания исключений.
Данный подход является обязательным, потому что гарантирует максимально раннее обнаружение проблемы. Игнорирование подхода приводит к проблемам в самых неожиданных местах. Программа может вести себя как корректная, хотя содержит в себе большое количество ошибок, пока очередная проблема не приведет к лавине. Примеры неожиданно всплывших проблем: https://software-testing.ru/library/testing/general-testing/2082-horrible-bugs
Требуется производить проверку контрактов:
- предусловий: с помощью assert в начале функции. Пример: Указатель: может быть нулевым? Нет? assert.
- инвариантов: по ходу выполнения функции. Пример: по ходу алгоритма нужно произвести удаление элемента из контейнера. Можно проверить, что этот элемент вообще присутствует в контейнере.
- постусловий: В конце функции и с помощью тестов. Пример: в результате удаления вершины из списка она не должна быть достижима из головы списка. Это можно провалидировать с помощью assert.
Проверки контрактов упрощают восприятие кода и могут при определенном стечении обстоятельств заменять документацию.
Q: но ведь проверка контракта может быть медленной, теряем производительность
A: используйте assert для медленных проверок, если нужна производительность - используется release режим сборки, туда эти проверки не попадут
2. Стиль кода совпадает во всем проекте.
Либо везде табуляции для отступов, либо везде пробелы. Именование переменных либо везде snake_case, либо везде camelCase. Желательно отделять разные сущности друг от друга написанием. Например, можно выделять:
- МАКРОСЫ()
- КОНСТАНТЫ
- функцииКоторыеЧтоТоДелают()
- переменныеКоторыеЗачемТоПонадобились
- ИменаКлассовИСтруктур
Допустимы конфликты написания (когда по имени нельзя однозначно восстановить, какая это языковая конструкция), но не стоит для всего использовать одно и то же написание.
3. Каждая строчка кода что-то делает.
Если строчку кода можно удалить без изменения поведения программы, значит, ее нужно удалить.
4. В языке Си использовать void(void)
, а не void()
.
5. Отсутствие утечек памяти, Undefined Behaviour и других проблем Ваша программа должна компилироваться и корректно завершаться, а соответствующая утилита не должна находить какие-либо проблемы:
- в debug и release (-DNDEBUG) режимах сборки
- будучи запущенной из-под gdb
- будучи запущенной из-под valgrind
- после компиляции с -fsanitize=address
- после компиляции с -fsanitize=undefined
- после компиляции с -fsanitize=leak
- на разных версиях разных компиляторов (gcc, clang, msvc, ...)
включая комбинации этих опций, кроме случаев ошибок в самих утилитах и несоответствия компилятора Стандарту. (Да, и то, и то бывает.)
6. Именование должно быть понятным кому угодно, не только лишь Автору, но и всем. Имя функции должно отражать особенности ее поведения. Имя переменной должно быть говорящим. Лучше всего, если вне контекста можно понять, за что отвечает / что делает та или иная функция, структура, переменная. Стандарт языка в этом смысле не является примером для подражания.
Этот раздел не может быть формализовать и ложится целиком и полностью на здравый смысл. Здесь зачастую нет "идеального" решения, и если вам не удается достичь совершенства - не расстраивайтесь, таких как вы - легион. Проблема именования является одной из ключевых в программировании, вызывает большое количество дискуссий, требует много времени и внимания разработчиков.
7. Если была допущена какая-то проблема в реализации функции, должен быть написан тест, детектирующий эту проблему.
8. Использование сторонних функций только из стандартной библиотеки языка, если противное явно не оговорено в задании.
В частности, написание C++ кода без привязки к платформе Linux; отсутствие POSIX-специфичных функций и структур. Не смотря на то, что целевая платформа - Linux, привычка писать платформенно-специфичный или компиляторо-специфичный код может однажды сыграть злую шутку. Комитет по стандартизации стремится к тому, чтобы не было необходимости писать такой код, включая новые и новые платформенно-независимые вещи в стандарт языка. Если "совсем никак", то лучше обернуть специфичную функцию: сделать size_t mygetline(char **lineptr, size_t *n, FILE *stream) {return getline(lineptr, n, stream);}
9. Не использовать exit где-либо, кроме main.cpp Представьте, что вы пользуетесь какой-то библиотекой. Позвали функцию из нее, а ей что-то не понравилось (не хватило памяти, запись на диск не удалась, ...) и она позвала в своих недрах exit. Это полная катастрофа, потому что на этом работа программы завершается, а в месте вызова вы об этом даже не узнаете. Это может быть очень болезненно: может быть, в оперативной памяти хранится результат длительных вычислений, или ценная информация, это могли быть данные, за которые нужно платить (обращения к платным сервисам) и много что еще. Главное - за вас кто-то другой решил, как программа должна себя вести. Никогда не используйте exit в библиотеках. Во всех заданиях прослеживается структура: сделать некоторый набор действий в рамках некоторой модели. Модель находится в одном месте, управляющая логика - в другом. Здесь проходит условная черта: модель - это библиотека, управляющая логика - конечный пользовательский код. Обработка ошибок должна осуществляться с помощью кодов возврата либо исключений.
10. Пространства имен Не писать ничего в глобальное пространство имен в заголовочных файлах. И не использовать `using namespace` на неограниченный scope (например, в начале .cpp файла).
To be continued.
Практика 2: Свиридкин
Практика 3: Лапшин
Практика 4: Гулецкий
Преподаватель: Артур Гулецкий (hatless.fox@gmail.com)
Префикс в теме письма: [C++TA]
Trac: huletski