Pull to refresh
337.73
PVS-Studio
Static Code Analysis for C, C++, C# and Java

60 антипаттернов для С++ программиста, часть 10 (совет 46 — 50)

Level of difficultyEasy
Reading time7 min
Views5.1K

1053_60_cpp_antipatterns_ru/image2.png


Перед вами обновлённая коллекция вредных советов для C++ программистов, которая превратилась в целую электронную книгу. Всего их 60, и каждый сопровождается пояснением, почему на самом деле ему не стоит следовать. Всё будет одновременно и в шутку, и серьёзно. Как бы глупо ни смотрелся вредный совет, он не выдуман, а подсмотрен в реальном мире программирования.


Я буду публиковать советы по 5 штук, чтобы не утомить вас, так как мини-книга содержит много интересных отсылок на другие статьи, видео и т. д. Однако, если вам не терпится, здесь вы можете сразу перейти к её полному варианту: "60 антипаттернов для С++ программиста". В любом случае желаю приятного чтения.


Вредный совет N46. Тренируйся на работе для IOCCC


Пишите код так, как будто его будет читать председатель жюри IOCCC и он знает, где вы живёте (чтоб приехать и вручить вам приз).


Это отсылка к фразе "Пишите код так, как будто поддерживать его будет склонный к насилию психопат, который знает, где вы живёте". Фраза сказана Джоном Ф. Вудсом, но ошибочно приписывается Стивену Макконнеллу, так как он упоминает её в своей книге "Совершенный код".


Обыгрывая эту фразу, даётся вредный совет – писать как можно более необычный, странный и непонятный код, в духе конкурса IOCCC.


IOCCC (International Obfuscated C Code Contest) — конкурс программирования, в котором задачей участников является написание максимально запутанного кода на языке C с соблюдением ограничений на размер исходного кода.


Почему непонятный код — это плохо, кажется очевидным. Но всё-таки — почему? Программист большую часть времени тратит не на написание кода, а на его чтение. Я не могу вспомнить источник и точные цифры, но, кажется, там говорилось, что он проводит за чтением более 80% времени.


Соответственно, если код тяжело прочитать и понять — это сильно замедляет разработку. Отсюда же берёт своё начало идея всем в команде оформлять код единообразным способом, чтобы он был привычен для осознания.


Вредный совет N47. Развлекайся, оформляя код


Если в C++ переносы строк и отступы незначимые, то почему бы не оформить код в виде зайчика или белочки?


Странное развлечение, которое сделает код нечитаемым для тех, кто будет его поддерживать. Далее сошлюсь на пояснение к предыдущему совету, так как оно подходит и сюда.


Впрочем, не буду уж совсем снобом и ханжой. Я иногда писал творческие или юмористические комментарии, и не вижу в этом ничего плохого. Мы все люди, и испытываем эмоции. Вполне естественно, если мы иногда выплеснем их в комментариях. А все мы знаем, как сильны иногда эти самые эмоции при программировании :).


Главное не вредить самому коду, не перебарщивать, не оскорблять кого-то.


Встретив в коде дракона, я отнесусь к этому нормально. И буду благодарен, что автор обратил моё внимание на что-то таким необычным способом.


//        .==.        .==.          
//       //`^\\      //^`\\         
//      // ^ ^\(\__/)/^ ^^\\        
//     //^ ^^ ^/6  6\ ^^ ^ \\       
//    //^ ^^ ^/( .. )\^ ^ ^ \\      
//   // ^^ ^/\| v""v |/\^ ^ ^\\     
//  // ^^/\/ /  `~~`  \ \/\^ ^\\    
//  -----------------------------

Кстати, рекомендую поглазеть на разное необычное в статье моего коллеги "Комментарии в коде как вид искусства".


Вредный совет N48. У каждого свой стиль


Выравнивание и единый стиль не дают раскрыться вашей индивидуальности и креативности. Это притеснение свободы личности и самовыражения. Каждый должен оформлять код так, как ему нравится.


Ладно-ладно, два предыдущих совета были слишком эксцентричны. Что по поводу адекватного самовыражения в именовании сущностей и оформлении кода?


Этого не стоит делать по следующим причинам:


  1. Собственный код, написанный в привычном индивидуальном стиле проще читать и понимать. Вот только над проектами трудятся команды. В результате всем будет постоянно тяжело, так как придётся работать с кодом, написанным по-разному. Пустая трата времени и умственных усилий. Если выбрать один стиль, то вначале все тоже будут испытывать дискомфорт. Но постепенно к стилю привыкнут, и он станет удобным для чтения и написания. Повысится общая производительность команды.
  2. Конфликт стилей. Часто нужно поправить только какой-то фрагмент кода. Если каждый делает это на свой лад, то код будет выглядеть как лоскутное одеяло. Получается, что вообще нет никакого стиля, сплошная анархия. Если же переделывать чужой код, с которым приходится работать, под себя, то это будет отнимать много времени. С точки зрения автора первоначального кода, это вообще вредное действие. В общем, это ненужная почва для личностных конфликтов. Конечно, правя чужой код, можно подстраиваться под стиль, в котором он написан. Но, во-первых, это сложно, а во-вторых, ты всё равно точно не знаешь, какой именно стиль у твоего коллеги.
  3. То, что свой стиль нравится человеку, вовсе не значит, что он хороший. Есть множество приёмов, когда написание кода определённым образом помогает избежать ошибок. Некоторые из таких приёмов я описывал в мини-книге "Главный вопрос программирования, рефакторинга и всего такого". Поэтому полезно опытными членами команды совместно разработать и внедрить единый для всех стандарт кодирования.

Надеюсь, я был убедителен. Очень полезно в команде иметь стандарт кодирования. За основу можно взять, например Google C++ Style Guide или любой другой. Затем адаптировать для себя. Дополнительным источником для вдохновения могут стать:


  • уже не раз упомянутая здесь книга "Совершенный код" С. Макконнелла (ISBN 978-5-7502-0064-1);
  • Ален И. Голуб. "Веревка достаточной длины, чтобы… выстрелить себе в ногу." Мне лично она не очень понравилась, но я не могу про неё не вспомнить. Это классика;
  • Standard C++ Foundation. FAQ: Coding Standards.

Со стилем программирования и стандартом кодирования связана тема форматирования кода. Если то, как именуются сущности, можно проверять на обзорах кода, то с форматированием могут помочь различные инструменты. Главное — договориться, как ваша команда форматирует код, а дальше — дело техники:


  1. clang-format;
  2. Best C++ Code Formatter/Beautifier;
  3. Are there any lint tools for C and C++ that check formatting?
  4. Is there any tool to standardize format of C++ code?

Вредный совет N49. Перегрузи всё


Перегрузите как можно больше операторов, в том числе и не арифметических, для как можно большего количества типов. Придавая операторам другой смысл, вы приближаетесь к созданию своего диалекта языка. Свой язык – это прикольно. А если ещё и макросы к делу подключить...


Перегрузка операторов — это более изящный вызов функций. Например, она позволяет использовать операторы + и = для строк. Это помогает писать изящный код конкатенации строк:


result = str1 + str2;

Согласитесь, это более красиво, чем:


result.assign(str1.strcat(str2));

Использовать перегрузку операторов следует только тогда, когда это упростит написание кода, как было показано в примере. Неуместное же использование, наоборот, затруднит чтение. Если действие перегруженных операторов интуитивно понятно, это хорошо. Если нет — это вредно.


Пусть A, B, C — это экземпляры класса матрицы. Тогда следующий код очевиден без пояснений:


A = B * C;

Другое дело:


A = B && C;

Этот код уже интуитивно не понятен. Конечно, можно посмотреть, что делает оператор && с матрицами. И, возможно, если это какая-то частая операция, действительно есть смысл использовать такую перегрузку для более компактного написания кода. Однако, я думаю вы понимаете, что, чем больше неочевидных действий выполняют перегруженные операторы, тем сложнее понимать код. Перегрузка начинает в этом случае усложнять код, а не упрощать.


P.S. Кстати, однажды Бьёрн Страуструп в качестве шутки предложил разрешить перегружать пробел: Generalizing Overloading for C++2000.


Вредный совет N50. Не верь в эффективность std::string


Универсальный std::string – это неэффективно. Можно ловчее и эффективнее использовать realloc, strlen, strncat и так далее.


То, что производительность программы можно существенно увеличить, отказавшись от класса std::string, является мифом. Но этот миф имеет под собой основание.


Дело в том, что раньше распространённые реализации std::string действительно оставляли желать лучшего. Так что, пожалуй, мы имеем дело даже не с мифом, а с устаревшей информацией.


Поделюсь собственным опытом. Начиная с 2006 года, мы разрабатываем статический анализатор PVS-Studio. В 2006 году он назывался Viva64, но это не имеет значения. Изначально в анализаторе мы широко использовали как раз стандартный класс std::string.


Шло время. Анализатор развивался, в нём появлялось всё больше диагностик, и с каждой версией он работал всё медленнее :). Пришло время задуматься над оптимизацией кода. Одним из узких мест, на которое указал профилировщик, оказалась работа со строками. И тогда настало время цитаты "в любом проекте рано или поздно появляется свой собственный класс строки". К сожалению, я не помню, ни откуда эта цитата, ни момент, когда именно это произошло. Кажется, это был 2008 или 2009 год.


Анализатор в процессе своей работы создаёт большое количество пустых или очень коротких строк. Мы написали свой собственный класс строки vstring, эффективно выделяющий память для таких строк. С точки зрения публичного интерфейса наш класс повторял std::string. Собственный класс строки повысил скорость работы анализатора приблизительно на 10%. Крутое достижение!


Этот класс строки служил нам долгие годы, пока на конференции C++ Russia 2017 я не побывал на докладе Антона Полухина "Как делать не надо: C++ велосипедостроение для профессионалов". В нём он рассказал, что уже много лет класс std::string хорошо оптимизирован. А те, кто использует свой собственный класс строки, являются ретроградами и динозаврами :).



Антон разобрал в своём докладе, какие оптимизации сейчас используются в классе std::string. Например, из самого простого – про конструктор перемещения. Меня же больше всего заинтересовала Small String Optimization.


Оставаться динозавром не хотелось. Мы провели эксперимент по обратному переходу с самодельного класса vstring к std::string. Для начала мы просто закомментировали класс vstring и написали using vstring = std::string;. Благо после этого потребовались незначительные правки кода в других местах, так как интерфейсы класса всё ещё почти полностью совпадали.


И как изменилось время работы? Никак! Это значит, что для нашего проекта универсальный std::string стал точно так же эффективен, как наш собственный специализированный класс, спроектированный нами с десяток лет назад. Здорово! Можно убрать один велосипед из кодовой базы проекта.


Однако мы говорили о классах. А во вредном совете предлагается спуститься на уровень функций языка C. Я сомневаюсь, что, используя эти функции, удастся написать более быстрый и надёжный код, чем в случае использования класса строки.


Во-первых, обработка С-строк (нуль-терминированных строк) провоцирует частое вычисление их длины. Не храня отдельно размер строк, сложно написать высокопроизводительный код. А если длина хранится, то мы вновь приближаемся к аналогу строкового класса.


Во-вторых, сложно написать надёжный код с использованием таких функций, как realloc, strncat и так далее. По опыту обзора ошибок в различных проектах можно констатировать, что код, использующий эти функции, прямо-таки "притягивает" к себе ошибки. Примеры ошибочных паттернов при использовании: strlen, strncat, realloc.


Об этой мини-книге


Автор: Карпов Андрей Николаевич. E-Mail: karpov [@] viva64.com.


Более 15 лет занимается темой статического анализа кода и качества программного обеспечения. Автор большого количества статей, посвящённых написанию качественного кода на языке C++. С 2011 по 2021 год удостаивался награды Microsoft MVP в номинации Developer Technologies. Один из основателей проекта PVS-Studio. Долгое время являлся CTO компании и занимался разработкой С++ ядра анализатора. Основная деятельность на данный момент — управление командами, обучение сотрудников и DevRel активность.


Ссылки на полный текст:



Подписывайтесь на ежемесячную рассылку, чтобы не пропустить другие публикации автора и его коллег.

Tags:
Hubs:
Total votes 12: ↑11 and ↓1+10
Comments15

Articles

Information

Website
pvs-studio.com
Registered
Founded
2008
Employees
31–50 employees