Уважаемые коллеги-программисты, предлагаю поделиться в комментариях примерами ошибок, которые на ваш взгляд можно обнаружить в программе еще на этапе ее написания. Наверняка у всех были ситуации, когда исправляя после часовой отладки ляп, вы вздыхали «эх, ну что же мне компилятор здесь предупреждение не выдал».Мне интересны в первую очередь паттерны ошибок, допускаемых в программах на Си++. Но я сознательно не стал помещать этот пост в раздел «Си++». Приводите примеры ошибок из других языков. Часто рассматривая ошибку, ��ожно придумать ее аналог на другом языке.
Ошибки мне нужны для создания нового уникального набора правил диагностики ошибок общего типа. Правил, которые действительно актуальны, которые найдут ошибки не в абстрактных приложениях, а в данных нам в ощущениях. Неинтересно уже искать в тексте завалявшиеся случайно триграфы. Ни разу не видел ошибку, связанную с триграфом. А вот опечаток, где для очистки строки вместо str.clear() написано str.empty(), полным-полно. Например, я писал про такой пример здесь. И ведь такие ошибки не находятся существующими инструментами! Поэтому мы и идем по пути создания нового, а не повторения старого.
Теперь попробую пояснить, про какие же ошибки мне хочется услышать и как.
Начну с примера самой банальной опечатки.
double a; a = 1,536;
Вместо точки случайно написана запятая. В результате данная строчка эквивалентна "(a = 1), 536;" и переменная 'a' примет значение 1. Компилятор естественно промолчит (по крайней мере, Visual C++).
Уверен, многие уже готовят в голове комментарий на тему, что такую ошибку может сделать только школьник. Зря. Никто не застрахован от таких ошибок. Эту ситуацию описал один из лучших специалистов по программированию, которых я знаю. Это Дмитрий Вьюков, обладатель титула «Мастер программирования, Черный пояс Intel». Автор множества статей и проекта Relacy Race Detector.
Вот его сообщение на сайте RSDN по поводу этой самой запятой. Естественно я не мог не обратить внимания на этот пост. Ошибка вполне реальна, актуальна и может быть выявлена при статическом анализе исходного кода. Диагностика подобных ошибок была реализована мной в PVS-Studio.
Пойдем дальше. Очень легко забыть, что std::remove() не удаляет элементы, а только сдвигает их. И как следствие должен использоваться в паре с функций erase(). Про это сделала хорошую заметку Елена Сагалаева (автор блога «Алёна C++»): "std::remove и std::remove_if на самом деле ничего не удаляют".
Эта также распространенная, красивая, актуальная, высокоуровневая ошибка. Она мне очень нравится. В реальном приложении она может выглядеть так (библиотека ZThreads):
void unregisterThread() {
Guard<TaskQueue> g(_taskQueue);
std::remove(_threads.begin(), _threads.end(), ThreadImpl::current());
}Этот фрагмент был найден PVS-Studio, после реализации соответствующей проверки, созданной после прочтения статьи Алёны.
Следующее правило придумал я сам, основываясь на личном опыте. Бывало, да и сейчас бывает, что я делаю опечатки и использую не то имя переменной. Некоторые такие ошибки можно выявить автоматически. Например, подозрительно, когда одной переменной подряд присваивается разное значение. После реализации соответствующей диагностики с помощью PVS-Studio сразу обнаружилось, например, такая ошибка в библиотеке Win32++:
class CSize : public SIZE
{
...
CSize(POINT pt) { cx = pt.x; cx = pt.y; }Приведу пример еще одного обсуждения, из которого можно составить правило для статического анализа. Вот здесь люди долго не могли понять, что через указатель на базовый класс нельзя работать с массивом производных классов. И как это обычно бывает, винили «глючный компилятор». В дискуссии с толку может сбить обсуждение оператора delete, поэтому приведу свой пример:
class A
{
int a;
};
class B : public A
{
int b;
};
void FOO()
{
B array[5];
A *p = array;
p[3].a = 1; //Пишем не пойми куда
}Размер классов A и B различен, а, следовательно, array[i] и p[i] адресуются к различным участкам памяти.
Это очень хороший пример, где статический анализ может сохранить массу нервных клеток и времени. Правило для диагностики таких ошибок в PVS-Studio пока не сделано, но в план развития записано.
Я описал разные примеры, как на основе обсуждений в форумах, статей, личном опыте, можно составить интересные правила анализа. Я буду рад, если вы поделитесь своими примерами или ссылками на подобные примеры.
P.S.
Если вам недоступна возможность комментирования статьи, то прошу писать мне на ящик karpov[@]viva64.com или через форму для связи.
