You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Соответствие стилю кодирования (см /coding-conventions)
** В C++ репозиториях должен присутствовать файл .clang-format, автоматизирующий форматирование
Артефакты сборки в репозитории храниться не должны и должны быть добавлены в .gitignore. Это можно указать при создании репозитория. Также можно скачать .gitignore отсюда: https://github.com/github/gitignore
Требования к коду
Функции, классы, переменные должны иметь понятные и логичные имена.
Дублирование кода -- зло. Дублирующихся фрагментов кода нужно практически всегда избегать. Это относится как к основной программе, так и к тестам.
Размеры функций должны быть небольшими. Функция должна выполнять одну логическую задачу.
Требования к программе
Если в задании требуется написать тесты, их надо написать.
Все основные кейсы перед сдачей программы должны быть протестированы.
При ручном и автоматическом тестировании не забывайте проверять граничные случаи.
Программа должна компилироваться без предупреждений компилятора во всех конфигурациях и платформах.
Объекты в функцию следует передавать по константной ссылке, если функция не модифицирует их состояние. Легковесные объекты (данные содержат 1-2 примитивных поля) передавать по константной ссылке выгоды нет, лучше по значению.
Исключение из предыдущего правила: у аргумента метода есть move-конструктор, а метод сохраняет объект в поле класса. В этом случае выгодно передать по значению и выполнить присваивание с move:
classPerson
{
public:explicitPerson(std::string name)
: m_name(std::move(name))
{
}
private:
std::string m_name;
};
intmain()
{
// Будет создан временный объект типа string со значением Ivan. Созданная строка будет перемещена в поле m_name
Person p{"Ivan"};
}
Отступы в коде должны задаваться либо табуляциями, либо пробелами. В последнем случае - четырьмя пробелами. Смешивание пробелов и табуляций для отступов в коде не допускается (за исключением ситуаций, когда это настолько необходимо, что сможете убедить в этом преподавателя). Использование табуляций предпочтительнее, т.к. совпадает с текущими религиозными убеждениями преподавателя.
Длина строки кода должна быть такой, чтобы помещаться в экране преподавателя (которая зависит от текущего масштаба в его IDE). Стремитесь к тому, чтобы она была в не более 80-100 символов. Есть плагины (или настройки) к IDE, которые позволяют визуализировать допустимую ширину.
Имена и структура тестов должны играть роль спецификации на тестируемую функцию или класс, а не просто перечислить ситуации, в которых вы проводите испытание класса или функции.
// плохо, так как описывает ситуацию, но не требованияTEST_CASE("TVSet turning on")
{
TVSet tv;
CHECK(tv.GetChannel() == 0);
tv.TurnOn();
CHECK(tv.IsTurnedOn());
CHECK(tv.GetChannel() == 1);
}
// хорошо. Так как описывает требование к классу TVSet и ограничивает размеры теста определённым сценариемTEST_CASE("TVSet after turning on selects 1st channel")
{
TVSet tv;
CHECK(tv.GetChannel() == 0);
tv.TurnOn();
CHECK(tv.IsTurnedOn());
CHECK(tv.GetChannel() == 1);
}
Для инициализации полей класса следует использовать списки инициализации конструктора или задавать значения в объявлении самого класса
classPerson
{
public:explicitPerson(std::string name)
{
// плохо (сперва поле name сконструировалось конструктором по умолчанию, а потом выполнена операция перемещающего присваивания)
m_name = std::move(name);
}
private:
std::string m_name;
};
classPerson
{
public:// хорошо (поле m_name сразу проинициализировано путём перемещения из name)explicitPerson(std::string name)
: m_name(std::move(name))
{
}
private:
std::string m_name;
};
методы класса не меняющие его состояние, должны быть константными
Исключения следует ловить по константной ссылке, а не по значению, чтобы избежать срезки (slicing). В редких случаях можно ловить по неконстантной ссылке, если требуется модифицировать пойманный объект исключений перед перевыбросом его.
При перевыбросе исключения следует использовать throw;, а не throw ex;, чтобы избежать срезки.
try
{
throwstd::invalid_argiment("oops");
}
catch (const std::exception& ex)
{
// плохо, так как будет перевыброшена лишь копия std::exceptionthrow ex;
}
try
{
throwstd::invalid_argiment("oops");
}
catch (const std::exception& ex)
{
// хорошо, так как будет перевыброшено то же самое исключение, какое было пойманоthrow;
}
В C++ у std::exception нет доступного конструктора, принимающего текст сообщения (это есть MS Visual C++, но в других компиляторах нет).
// плохо - непортируемоthrowstd::exception("argument is out of range");
// хорошоthrowstd::out_of_range("argument is out of range");
Тип выбрасываемого исключения должен соответствовать возникшей проблемной ситуации
В проектах на Visual C++ крайне рекомендуется настроить запуск проекта с тестами по окончании сборки (Post Build Event): TODO: сделать ссылку на youtube-видео
Переменные следует объявлять как можно ближе к месту их первого использования (желательно, совмещая с инициализацией).
Оператор присваивания должен возвращать ссылку на левый аргумент
Копирующий оператор присваивания должен принимать правый аргумент по константной ссылке
Как правило, оператор присваивания должен обеспечивать строгую гарантию безопасности ислючений (есть лекция /lectures/05)
Тесты должны не только проверять успешность или неудачу при выполнении модифицирующей состояние объекта операции, но еще и сравнивать состояние объекта после операции с ожидаемым. Если в разных тестах используются однотипные проверки состояния (состоящие из нескольких действий), то полезным будет выделить их в функции вида:
voidExpectOperationSuccess(SomeObj & obj, const function<bool(SomeObj & obj)> & op, int expectedProperty1, const string & expectedProperty2, ...)
{
BOOST_REQUIRE(op(obj)); // ожидаем, что операция вернет true (успех)// Сравниваем состояние свойства объект с ожидаемымBOOST_CHECK_EQUAL(obj.GetProperty1(), expectedProperty1);
BOOST_CHECK_EQUAL(obj.GetProperty2(), expectedProperty2);
...
}
voidExpectOperationFailure(const SomeObj & obj, const function<bool(SomeObj & obj)> & op);
{
autoclone(obj); // сделали клон объектаBOOST_REQUIRE(!op(clone)); // ожидаем, что операция завершится неуспешно (передаем клон)// проверяем, что после выполнения операции состояние клона не отличается от оригинала // (операция в случае неудачи оставляет объект в состоянии, в котором он пребывал до операции)BOOST_CHECK_EQUAL(clone.GetProperty1(), obj.GetProperty1());
BOOST_CHECK_EQUAL(clone.GetProperty2(), obj.GetProperty2());
...
}
Для объявления пустой строки в C++ следует использовать конструктор по умолчанию, а не конструктор, инициализирующий ее строковым литералом "". Конструктор по умолчанию работает быстрее, требует меньше символов для ввода, и является для c++ идиоматичным.
Если при проверке программы теструющий её скрипт обнаружил ошибку, скрипт должен завершиться с ненулевым кодом возврата.
Если приложение имеет параметры командной строки, пользователю надо выдать краткую справку о синтаксисе командной строки