Skip to content

Latest commit

 

History

History
159 lines (148 loc) · 12.9 KB

README.md

File metadata and controls

159 lines (148 loc) · 12.9 KB

На что обращать внимание при проверке

  • Соответствие стилю кодирования (см /coding-conventions) ** В C++ репозиториях должен присутствовать файл .clang-format, автоматизирующий форматирование
  • Артефакты сборки в репозитории храниться не должны и должны быть добавлены в .gitignore. Это можно указать при создании репозитория. Также можно скачать .gitignore отсюда: https://github.com/github/gitignore

Требования к коду

  • Функции, классы, переменные должны иметь понятные и логичные имена.
  • Дублирование кода -- зло. Дублирующихся фрагментов кода нужно практически всегда избегать. Это относится как к основной программе, так и к тестам.
  • Размеры функций должны быть небольшими. Функция должна выполнять одну логическую задачу.

Требования к программе

  • Если в задании требуется написать тесты, их надо написать.
  • Все основные кейсы перед сдачей программы должны быть протестированы.
  • При ручном и автоматическом тестировании не забывайте проверять граничные случаи.

Часто встречающиеся замечания

  • C.35: A base class destructor should be either public and virtual, or protected and nonvirtual. Разобраться и уметь объяснить
  • Программа должна компилироваться без предупреждений компилятора во всех конфигурациях и платформах.
  • Объекты в функцию следует передавать по константной ссылке, если функция не модифицирует их состояние. Легковесные объекты (данные содержат 1-2 примитивных поля) передавать по константной ссылке выгоды нет, лучше по значению.
  • Исключение из предыдущего правила: у аргумента метода есть move-конструктор, а метод сохраняет объект в поле класса. В этом случае выгодно передать по значению и выполнить присваивание с move:
class Person
{
public:
    explicit Person(std::string name)
        : m_name(std::move(name))
    {
    }
private:
    std::string m_name;
};

int main()
{
    // Будет создан временный объект типа string со значением Ivan. Созданная строка будет перемещена в поле m_name
    Person p{"Ivan"};
}
  • Отступы в коде должны задаваться либо табуляциями, либо пробелами. В последнем случае - четырьмя пробелами. Смешивание пробелов и табуляций для отступов в коде не допускается (за исключением ситуаций, когда это настолько необходимо, что сможете убедить в этом преподавателя). Использование табуляций предпочтительнее, т.к. совпадает с текущими религиозными убеждениями преподавателя.
  • Для хранения размеров и позиций в контейнерах STL следует использовать тип size_t а не int/unsigned int, т.к. разрядность size_t и int может отличаться (64 бита против 32 на 64-битных платформах) http://www.viva64.com/ru/w/V104/print/ http://www.viva64.com/ru/w/V108/print/
  • В заголовочных файлах using namespace писать не следует. И вот почему:
  • C.128: Virtual functions should specify exactly one of virtual, override, or final. Разобраться и уметь объяснить. ** Исключение из предыдущего правила: в переопределённом деструкторе класса-наследника override можно не писать.
  • Длина строки кода должна быть такой, чтобы помещаться в экране преподавателя (которая зависит от текущего масштаба в его 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);
}
  • Для инициализации полей класса следует использовать списки инициализации конструктора или задавать значения в объявлении самого класса
class Person
{
public:
    explicit Person(std::string name)
    {
        // плохо (сперва поле name сконструировалось конструктором по умолчанию, а потом выполнена операция перемещающего присваивания)
        m_name = std::move(name);
    }
private:
    std::string m_name;
};

class Person
{
public:
    // хорошо (поле m_name сразу проинициализировано путём перемещения из name)
    explicit Person(std::string name)
        : m_name(std::move(name))
    {
    }
private:
    std::string m_name;
};
  • методы класса не меняющие его состояние, должны быть константными
  • Исключения следует ловить по константной ссылке, а не по значению, чтобы избежать срезки (slicing). В редких случаях можно ловить по неконстантной ссылке, если требуется модифицировать пойманный объект исключений перед перевыбросом его.
  • При перевыбросе исключения следует использовать throw;, а не throw ex;, чтобы избежать срезки.
try
{
    throw std::invalid_argiment("oops");
}
catch (const std::exception& ex)
{
    // плохо, так как будет перевыброшена лишь копия std::exception
    throw ex;
}

try
{
    throw std::invalid_argiment("oops");
}
catch (const std::exception& ex)
{
    // хорошо, так как будет перевыброшено то же самое исключение, какое было поймано
    throw;
}
  • В C++ у std::exception нет доступного конструктора, принимающего текст сообщения (это есть MS Visual C++, но в других компиляторах нет).
// плохо - непортируемо
throw std::exception("argument is out of range");
// хорошо
throw std::out_of_range("argument is out of range");
  • Тип выбрасываемого исключения должен соответствовать возникшей проблемной ситуации
  • В проектах на Visual C++ крайне рекомендуется настроить запуск проекта с тестами по окончании сборки (Post Build Event): TODO: сделать ссылку на youtube-видео
  • Переменные следует объявлять как можно ближе к месту их первого использования (желательно, совмещая с инициализацией).
  • Оператор присваивания должен возвращать ссылку на левый аргумент
  • Копирующий оператор присваивания должен принимать правый аргумент по константной ссылке
  • Как правило, оператор присваивания должен обеспечивать строгую гарантию безопасности ислючений (есть лекция /lectures/05)
  • Тесты должны не только проверять успешность или неудачу при выполнении модифицирующей состояние объекта операции, но еще и сравнивать состояние объекта после операции с ожидаемым. Если в разных тестах используются однотипные проверки состояния (состоящие из нескольких действий), то полезным будет выделить их в функции вида:
void ExpectOperationSuccess(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);
    ...
}

void ExpectOperationFailure(const SomeObj & obj, const function<bool(SomeObj & obj)> & op);
{
    auto clone(obj); // сделали клон объекта
    BOOST_REQUIRE(!op(clone)); // ожидаем, что операция завершится неуспешно (передаем клон)
    // проверяем, что после выполнения операции состояние клона не отличается от оригинала 
    // (операция в случае неудачи оставляет объект в состоянии, в котором он пребывал до операции)
    BOOST_CHECK_EQUAL(clone.GetProperty1(), obj.GetProperty1());
    BOOST_CHECK_EQUAL(clone.GetProperty2(), obj.GetProperty2());
    ...
}
  • Для объявления пустой строки в C++ следует использовать конструктор по умолчанию, а не конструктор, инициализирующий ее строковым литералом "". Конструктор по умолчанию работает быстрее, требует меньше символов для ввода, и является для c++ идиоматичным.
  • Если при проверке программы теструющий её скрипт обнаружил ошибку, скрипт должен завершиться с ненулевым кодом возврата.
  • Если приложение имеет параметры командной строки, пользователю надо выдать краткую справку о синтаксисе командной строки