asvp
> for(size_t i = 0; i < vector.size(); i++) {
[байтофил моде он]
for(size_t i = vector.size( ); i ; i--) {
[байтофил моде офф]
[с++ моде он]
for(auto item : vector) {
[с++ моде офф]
Laynos
> я хочу научиться писать красивый и понятный код. Такой, который воспринимался бы на одном дыхании. Помогите пожалуйста советами...
По степени соотношения время/результат:
1. Работа в команде (притом надо сменить несколько коллективов - в одном свои правила устанавливаются, в другом - другие).
2. Практика.
3. Самообразование.
Если удастся смешать все три пункта, хорошим кодером ты станешь легко и непринужденно не минует и полгода.
У меня так уж вышло, что не было каких-то мегасложных приложений. И паттерны по факту почти не пригодились (ну да, я ж кодил на С++ чисто для хобби, вот там да, без них никуда. Но крестокодером работать не пришлось, и слава богу, был бы щас седым и бородатым). Тем не менее практика С++ очень помогает в будущем при проектировании программ, мне к примеру помогает до сих пор - уж очень много кода я переписывал на С++ в первое время, посему организм выработал привычку разрабатывать стройную архитектуру на лету и прорабатывать большинство вариантов.
Пример из последнего.
Требовалось сделать геокодирование с 3-ех источников (яндекс, SQL база, и местный серв). При том необходимо уметь их миксовать (т.е. если первый не вернул ничего - переходим к следующему) - и т.д.
Я потратил пару лишних недель в июне, чтобы все это работало по всем правилам ООП, т.е. - единый интерфейс, единые входные данные, все внутренности внутри одного большого менеджера.
В итоге я любые изменения в этот класс вносил за пару часов, а коллеги по Андроид-версии упарываются по сей день. Более того, насколько я знаю, там фишка по смешиванию вообще не реализована.
Еще один пример - компонент.
Допустим ты не знаешь, как клиент захочет, и не в курсе, какие именно всплывающие подсказки захочет клиент.
Поэтому моделится небольшой ряд примеров с одинаковым интерфейсом на разными реализациями.
В итоге при переделке экранов также экономится просто ТУЧА времени, благо смена одного компонента на другой - недолгая. Более того, можно их менять на лету, к примеру, какой-либо настройкой.
Откуда все это? Да все из тех же граблей на С++, в котором стоимость изменений просто несопоставима с objective-C.
CasDev
> В итоге я любые изменения в этот класс вносил за пару часов
Ну это слабый показатель. Важнее как много времени потребуется другому разработчику внести изменения.
rusk
> Ну это слабый показатель. Важнее как много времени потребуется другому
> разработчику внести изменения.
Нужно еще сравнить уровень развития того, кто вносит изменения. Например, код написан с использованием всеми любимого шаблона MVC. Быдлокодер, не зная данного паттерна может в лучшем случае вбить в стройную архитектуру свой костыль, в худшем случае все поломать, путем перписывания. Для знающего внести изменения - дело нескольких минут, для быдлокодера, в силу ограниченности ума, почти недостижимая задача.
rusk
> Важнее как много времени потребуется другому разработчику внести изменения.
Я думаю, если это человек с улицы, то ему придется вникать в другие детали нисколь не меньше, поскольку логика у того приложения уже хромает на обе ноги.
Впрочем, корни проблем на самом деле там растут с серверной части (а если еще дальше - то план разработки первично являл собой ветвистое дерево фич, которое собиралось из пожеланий разных клиентов. Допусти одному клиенту моча двинула в левое полушарие, второму - в другое место, а список вводимых фишек столбить начали уже тогда, когда было написано целое море кода по знаменитейше-наикрутейшему принципу - "вЪчерасьнада").
dds
> Например, код написан с использованием всеми любимого шаблона MVC. Быдлокодер, не зная данного паттерна может в лучшем случае вбить в стройную архитектуру
> свой костыль, в худшем случае все поломать, путем перписывания. Для знающего внести изменения - дело нескольких минут, для быдлокодера, в силу
> ограниченности ума, почти недостижимая задача.
Было дело, когда делали довольно простую игрушку. Впрочем, тому парнишке нужна была зарплата онли, о коде он не слишком много думал.
Я тогда был ярым сторонником итеративной разработки и не смотрел, что парень мержит в ветку. В итоге, когда по истечении двух недель сел проверять, просто за голову схватился.
тема про красивый код, но красивого кода в теме нет. непорядок!
graphIT
> Разве нынешние компиляторы с++ не настолько умные чтоб делать это
> автоматически?
Допускаю, что возможно компилятор способен произвести такую оптимизацию для "родных" контейнеров своей стандартной библиотеки, которую пилят те же люди, что и сам компилятор.
Просто потому, что эти люди понимают тонкости языка, и знают, как сделать так, что бы компиль максимально эффективно обработал конструкцию.
Для нестандартных контейнеров действует правило inline.
Если компилятору доступно туловище метода, и он может сделать его inline, тогда может оптимизировать.
Однако, если туловище не доступно, либо поле помечено как volatile,
либо в туловище функции есть вызовы, которые не прошли тест на inline (компилятор опасается сайд-эффектов, либо по каким то другим причинам не имеет право сделать inline),
либо ещё по каким причинам - он может отказаться от оптимизации, и каждый раз будет заново вычислять значение size().
Известный факт: в давние времена квалификатор const помогал компиляторам оптимизировать выражения.
Компиляторы могут закладываться, что раз конст - значит не изменится, а если не изменяется, значит можно не опасаться эффектов, и делать inline.
В этом смысле код:
const auto num = someContainer.size(); for( size_t i = 0; i < num; ++i) Proccess( someContainer );
прост для написания, и хорош для читабельности. Например в пошаговой отладке нам удобно будет увидеть количество элементов.
Но самое главное: такой код с высокой степенью вероятности сможет оптимизировать даже отсталый компилятор. И это будет работать для любых контейнеров.
Такую форму записи можно использовать в шаблонах, которые можно инстанцировать любыми контейнерами: и стандартными, и не стандартными.
Резюмируя: для упрощения громоздких конструкций, и удобства чтения кода можно ( и желательно ) делать столько промежуточных переменных значений, сколько понадобится.
Помеченные квалификатором конст, все они без труда будут оптимизированы даже отсталым компилятором.
Хорошо людям.
Хорошо компилятору.
Хорошо для приложения.
Laynos
не знаю, как надо, могу рассказать, как учился сам. в порядке убывания важности:
1) не бойся переосмысливать и переписывать свой старый(но живой) код согласно своим текущим знаниям в проектировании, оформлении и оптимизации. касается старых проектов, которые тебе по-прежнему интересны.
2) всегда ориентируйся на чьи-то правила оформления кода. gnu code convention, google code convention, C# code convention, java code convention - они разработаны для разных языков, но все подходят для C++. чем дольше ты игнорируешь общепринятые стандарты оформления, тем сложнее будет привыкнуть, когда ты осознаешь эту необходимость.
3) работай в команде более опытных чем ты программистов и читай более серьёзных, чем твой текущий уровень, программ.
4) полезно работать в разных проектах с разными правилами оформления и построения кода.
Kartonagnick
> Вот если подсунуть ни то, ни другое, ни третье, но такое, что умеет кастиццо к
> нескольким - ну это времени компиляции заломается.
> проблема будет решена в течении нескольких секунд.
>
> в чем ад то?
Верно, нужно чтоб было неявное преобразование.
Вариантов ада 2:
1) компилятор не сможет выбрать (error). Прийдется переделывать интерфейсы чтобы мог, возможно много. Вариант вручную выбрать нужное преобразование не рассматриваю - допустим для примера такой вариант неприемлем.
2) компилятор родит (неправильную) цепочку преобразований, о которой никто и не думал. Например преобразует сложный класс в строку, а потом сконструирует другой сложный класс из строки (это если слишком много всяких операторов приведения). Прийдется отрезать лишние интерфейсы, но сначала до этого еще дебагером докопаться нужно.
shekh
> Вариантов ада 2:
> 1) компилятор не сможет выбрать (error). Прийдется переделывать интерфейсы
> чтобы мог, возможно много. Вариант вручную выбрать нужное преобразование не
> рассматриваю - допустим для примера такой вариант неприемлем.
Тут важно понять причину нарушения контракта с классом.
Ваш класс принимает кисок и собачек. Вы ему пихаете мышку. Зачем?
> 2) компилятор родит (неправильную) цепочку преобразований, о которой никто и не
> думал.
Такое случается и легко лечится без изменений в дизайне использования.
> Например преобразует сложный класс в строку, а потом сконструирует
> другой сложный класс из строки (это если слишком много всяких операторов
> приведения).
А вот такое уже не случается. Ваш тезис противоречит правилам языка с++
Либо приведите пример подобных преобразований.
Занятная статья о тёмной стороне кода - http://habrahabr.ru/company/scrumtrek/blog/168485/
Чтобы писать понятный людям код, надо прекрасно знать Английский язык.
Стив Макконнелл - Совершенный код
Обязательна к прочтению, в итоге к похожим соображениям и придешь.
1Man1
> От size-1 до 0
>
> for(size_t i = vector.size(); --i >=0;)
Ты свой код запускал? Он точно работает? :)
1Man1
> Спасибо, нужен знаковый int
Исправил, но теперь большинство компиляторов будут ворнинг кидать :)
Тема в архиве.