Comments 113
Стандарт С++ не гарантирует, что float(0) и даже int(0) реализуются как «все биты 0»Тем не менее стандарт гарантирует, что при приведении float(0) или int(0) к bool мы получим true.
Так что этот совет про
// ПЛОХО if (float_num) {} if (int_num) {}я бы исключил из статьи.
+19
при приведении float(0) или int(0) к bool мы получим truefalse конечно же, опечатался.
+19
Согласен только частично :-) Моё объяснение, согласен, не точное… даже неверное… позор мне, в общем.
Но вот сам совет хороший. Он даёт не только указанное мной преимущество.
Во-первых, он сразу проверяет тип, чем помогает не совершать ошибки.
Во-вторых, использовать не bool просто не концептуально. Это пережиток C, которому не место в C++. Согласитесь?
Но вот сам совет хороший. Он даёт не только указанное мной преимущество.
Во-первых, он сразу проверяет тип, чем помогает не совершать ошибки.
Во-вторых, использовать не bool просто не концептуально. Это пережиток C, которому не место в C++. Согласитесь?
-2
Во-первых, он сразу проверяет тип, чем помогает не совершать ошибки.Если вы проверяете на равенство/неравенство нулю, то тип вам не важен, я думаю.
Во-вторых, использовать не bool просто не концептуально.Условие в if и while приводится к bool, если оно не bool. Писать if (x) вместо if (0 != x) это уже идиома. Чтобы поддержать эту идиому в классах определяется operator bool и operator!
Сравните
boost::shared_ptr<T> p; if (p) { ... } if (NULL != p.get()) { ... }
Первый вариант намного лаконичнее.
+3
Многие конструкции уже укоренились, например проверка указателя. Тут вопрос в том как это применять. Если я проверяю указатель — это одно, но если я использую if(x) для проверки знаменателя на равенство нулю — это уже совсем другое. Последний вариант, как и многие ему подобные, использовать само собой не стоит.
+2
Числа с плавающей точкой лучше проверять не на равенство .0, а на попадание в окрестность нуля. Потому что у вас всегда будет погрешность, кроме совсем тривиальных случаев.
+19
Соглашаюсь обеими руками! Не вношу в статью только потому, что она немного не об этом и без того уже слишком длинная. Пусть это замечание останется украшением обсуждения :-)
+2
Кстати проблема легко решается наличием всего пары строк:
или
Первый вариант сравнивает с постоянным epsilon = 1.0E-4, второй с процентом от меньшего числа.
static inline bool fuzzyCompare1(float p1, float p2) { return abs(p1 - p2) <= 1.0E-4; }
или
static inline bool fuzzyCompare2(float p1, float p2) { return abs(p1 - p2) <= 0.00001f * min(abs(p1), abs(p2)); }
Первый вариант сравнивает с постоянным epsilon = 1.0E-4, второй с процентом от меньшего числа.
+3
Про то, что for(;;) это плохо — тоже глупость. Это легальный способ написать бесконечный цикл не получив предупреждения «conditional expression is constant».
+10
Согласен. В плане легальности, все три способа, которые я привожу, эквивалентны. Но тут речь не о легальности, а об… эстетике.
0
Норвежские программисты предлагают свой способ: doc.qtsoftware.com/4.5/qtglobal.html#forever
+4
for(;;) — самый корректный способ бесконечного цикла. уберите из плохих практик, а то плохому научите )
+1
Ну это спорный вопрос :-) вот тут совет 60
geosoft.no/development/cppstyle.html#Types
И я с ними согласен. В С++ (а речь именно про него) типы заслуживают особого уважения.
geosoft.no/development/cppstyle.html#Types
И я с ними согласен. В С++ (а речь именно про него) типы заслуживают особого уважения.
-1
Чтобы компилятор сразу же дёрнул вас за руку, некоторые люди вырабатывают привычку писать сравнения наоборот (признаюсь, я не смог её выработать в себе :-))Прийдется выработать привычку ставить максимальный уровень предупреждений и трактовать их как ошибки ;)
+1
Ох. Эта тема уже обсуждалась. Я принадлежу к людям, которые считают, что совершенство недостижимо :-)
0
>Описывайте сперва нормальный ход событий
Довольно часто встречаются такие ситуации:
if(isOk)
{
//~100 строк кода
}
else
{
setError();
return -1;
}
Такие блоки гораздо легче читать, если сначала описать более короткую последовательность действий.
Довольно часто встречаются такие ситуации:
if(isOk)
{
//~100 строк кода
}
else
{
setError();
return -1;
}
Такие блоки гораздо легче читать, если сначала описать более короткую последовательность действий.
+11
Та ну, здесь абсолютно правильно автор пишет. Вы что чаще будете читать — эти 100 строк кода, или 2 строки с обработкой ошибки?
-2
Та ну, я лучше сразу увижу две строчки обработки ошибки и перейду к остальной части кода. Две строчки мне не повредят никак. А вот в случае с автором, за сотней строк можно и не заметить обработку ошибки, что плачевно.
Всё, что для вас «абсолютно правильно» не означает, что это автоматически правильно для других. Автор описал достаточно спорные моменты и попытался обобщить, напялить на всех, а это вредно.
Всё, что для вас «абсолютно правильно» не означает, что это автоматически правильно для других. Автор описал достаточно спорные моменты и попытался обобщить, напялить на всех, а это вредно.
+10
Мне кажется, эти 100 строчек хорошо бы вынести в отдельную функцию и дать ей понятное имя. Так всем будет проще.
+10
Да, вынесение 100 строчек кода в отдельную функцию, во многих случаях оправданное решение. Читаемость кода повысится.
Но дальше возникают довольно-таки холиварные моменты. Одни готовы терпеть 100 строчек кода в одной из веток if'а, другие закроют глаза на узкоспециализированную функцию, использующуюся один раз и имеющую в параметрах разнородные данные (контексты, внутренние структуры разных уровней, буферы с данными, текущее значение счетчика (если снаружи цикл)). Это уже дело вкуса и, как правило, разработчики между собой договариваются, как в подобных случаях поступать.
Скажем, в команде, в которой сейчас я работаю, принято в функцию выносить фрагменты кода, которые используются два раза или более. А те 100 строк кода изрядно разбавляем комментариями с описанием что и зачем делается. Вполне возможно, что кому-то из здесь присутствующих неудобно следовать этому правилу. Главное, что всегда можно выбрать фломастер, вкус которого вам понравится.
Но дальше возникают довольно-таки холиварные моменты. Одни готовы терпеть 100 строчек кода в одной из веток if'а, другие закроют глаза на узкоспециализированную функцию, использующуюся один раз и имеющую в параметрах разнородные данные (контексты, внутренние структуры разных уровней, буферы с данными, текущее значение счетчика (если снаружи цикл)). Это уже дело вкуса и, как правило, разработчики между собой договариваются, как в подобных случаях поступать.
Скажем, в команде, в которой сейчас я работаю, принято в функцию выносить фрагменты кода, которые используются два раза или более. А те 100 строк кода изрядно разбавляем комментариями с описанием что и зачем делается. Вполне возможно, что кому-то из здесь присутствующих неудобно следовать этому правилу. Главное, что всегда можно выбрать фломастер, вкус которого вам понравится.
+1
самое приятное это когда мы разобрались с особыми случаями и забыли о них.
if (error_occured) {
return -1;
}
// no errors further
if (error_occured) {
return -1;
}
// no errors further
+12
кроме того такой стиль кодирования уменьшает вложенность и код выглядит проще
сравните
сравните
void f()
{
if(ok1)
{
do1();
if(ok2)
{
// а вот тут собственно код вашей фукнции - уже третий уровень вложенности
}
else
return -2;
}
else
return -1;
}
void f()
{
// проверим все условия
if(!ok1)
return -1;
do1();
if(!ok2)
return -2;
// теперь все гарантированно хорошо, можно сделать то что мы намеревались
// и никаких лишних {} и отступов
}
+6
а если такую обработку еще и отформатировать в виде:
то будет еще красивее.
Правда это противоречит одному из правил в статье, но на мой взгляд, такие ситуации, как раз являются исключением из этого правила.
void f() { // проверим все условия if(!ok1) return -1; do1(); if(!ok2) return -2; // теперь все гарантированно хорошо, можно сделать то что мы намеревались // и никаких лишних {} и отступов }
то будет еще красивее.
Правда это противоречит одному из правил в статье, но на мой взгляд, такие ситуации, как раз являются исключением из этого правила.
0
Как по мне, одним из основополагающих принципов является «функция должна иметь одну точку возврата». Множественные return-ы только запутывают.
-7
Это холиварное утверждение. Многоуровневая вложенность ифов запутывает не меньше.
Выбрасывание исключения между прочим — тоже может быть точкой выхода из функции, так что теперь, исключения не использовать?
Выбрасывание исключения между прочим — тоже может быть точкой выхода из функции, так что теперь, исключения не использовать?
+3
описанный мной пример, а также, скажем, исключения подтверждают, что это правило — полный отстой :)
+1
И за что заминусовали человека? Высказывание абсолютно верное, выведено такими личностями, как Кнут, Дейкстра и Вирт.
0
Ага, наверное поэтому у Кнута в каждой второй функции несколько ретурнов. Кстати, когда он писал на Паскале его и гоуту в конец функции не смущал, как заменитель ретурна, в те времена Exit'а в Паскале не было.
+2
Чтобы не быть голословным:
5 ретурнов, 1 гоуту
node *sum(p,q) /* compute the sum of two binary trees */ node *p,*q; { register node *pl,*ql; register int s; easy=1; if (!p) return q; if (!q) return p; pl=left(p); ql=left(q); s=compare(pl,ql); if (s==0) { @<Add |right(p)| to |right(q)| and append this to |succ(pl)|@>@; easy=0;@+return p; } else { if (s<0) @<Swap |p| and |q| so that |p>q|@>; q=sum(right(p),q); if (easy) goto no_sweat; else { ql=left(q); s=compare(pl,ql); /* does a carry need to be propagated? */ if (s==0) { /* yup */ change(&p->r,right(q)); recycle(ql);@+free_node(q); if (pl) succ(pl); else change(&p->l,get_avail()); return p; } else easy=1; /* nope */ } no_sweat: change(&p->r,q); return p; } }
5 ретурнов, 1 гоуту
+1
А теперь быстренько объясните, что делает этот код. Мне не понятно. :) (вы выдернули его из контекста, а у мои телепатические способности не позволяют его восстановить.)
ЗЫ ладно, вычеркните Кнута из списка.
ЗЫ ладно, вычеркните Кнута из списка.
-2
Дык видать народ не читал классики, чего уж там ;) И, кроме как, кучей ретурнов уже не умеют красиво организовать потом исполнения.
-1
Я читал не только классиков 60-х 70-х, но и современных классиков. Так вот Фаулер в «Рефакторинге» утверждает, что правило единственного выхода из функции нужно забыть как ошибку прошлого.
Мир не стоит на месте, поэтому, читайте современные книги.
Мир не стоит на месте, поэтому, читайте современные книги.
+1
Один советует одно, другой рекомендует другое. Для вас одно — для меня другое. Захламляйте код кучей точек выхода и сопровождающие попомнят вас не злым тихим словом.
-1
Мне кажется, что код, с несколькими точками выхода, который имеет 2 уровня вложенности читается и сапровождается намного проще, чем код с одной точкой выхода и четырьмя уровнями вложенности.
Не надо слепо верить словам Дейкстры (это правило придумал именно он), хотя, на вкус, как известно, все фломастеры… ну вы знаете.
Не надо слепо верить словам Дейкстры (это правило придумал именно он), хотя, на вкус, как известно, все фломастеры… ну вы знаете.
+1
Дык правило «один вход — один выход» возникло не просто так.
Ключевое слово тут «структурность». Больше структуры — легче рассуждать о поведении кода.
На этом же основываются и design patterns. Например, увидев в коде синглтон, программист сразу же начинает представлять себе, лол, что можно с ним делать, а что — нельзя.
Ключевое слово тут «структурность». Больше структуры — легче рассуждать о поведении кода.
На этом же основываются и design patterns. Например, увидев в коде синглтон, программист сразу же начинает представлять себе, лол, что можно с ним делать, а что — нельзя.
0
если в else return, то логичнее
if(!isOk)
{
setError();
return -1;
}
//~100 строк кода
if(!isOk)
{
setError();
return -1;
}
//~100 строк кода
+5
Такие ситуации не должны встречаться. Если у Вас получилась простыня на 100 строк, то стоит разбить их на функции. Читаемость кода повысится сильнее.
0
Статья как статья, а вот некоторые комментарии перед кусками кода улыбнули =)…
// ПОХУЖЕ вообще убило =). Извиняюсь за оффтоп.
// ПОХУЖЕ вообще убило =). Извиняюсь за оффтоп.
-10
В добавок к уже сказанному.
Например, мне проще выносить негатив в if, а обработку в else. К примеру, кусок кода:
if (some_error)
throw Error();
else
{
// make job
}
как по мне выглядит логичнее.
Ну и создание лишних переменных тоже зло. Опять же, как по мне, так легче в одном условии всё описать, чем плодить гору лишних переменных ради одного условия. Ясное дело, если они нужны далее, тогда вопросов нет. Но в противном случае, зачем их плодить?
Опять же, выражения:
if (readDdata(getFileNameFromArray(getEnvAsArray()))) {}
if (lid = getLabel() == curentLabel())
вполне читабельны и юзабельны. Не вижу проблемы.
Вам бы стоило сделать акцент на контингент. Для новичок читать исходники какого-нибудь embedded конечно сложно, но зачем адекватным людям усложнять себе же жизнь лишним мусором? :)
Например, мне проще выносить негатив в if, а обработку в else. К примеру, кусок кода:
if (some_error)
throw Error();
else
{
// make job
}
как по мне выглядит логичнее.
Ну и создание лишних переменных тоже зло. Опять же, как по мне, так легче в одном условии всё описать, чем плодить гору лишних переменных ради одного условия. Ясное дело, если они нужны далее, тогда вопросов нет. Но в противном случае, зачем их плодить?
Опять же, выражения:
if (readDdata(getFileNameFromArray(getEnvAsArray()))) {}
if (lid = getLabel() == curentLabel())
вполне читабельны и юзабельны. Не вижу проблемы.
Вам бы стоило сделать акцент на контингент. Для новичок читать исходники какого-нибудь embedded конечно сложно, но зачем адекватным людям усложнять себе же жизнь лишним мусором? :)
+2
Зачем после throw нужен else?
+4
просто пример выброса ошибки, замените на ProcessError(), без разницы. Смысл в «малом кол-ве кода»
0
Я к тому, что в случае с throw не нужен else c фигурными скобками, увеличивающий вложенность.
0
Я к тому, что просто хотел показать в первом блоке «малое кол-во кода» и первое, что пришло в голову — это throw. Я согласен, что пример говняный, но суть была не в самом throw, а показать, что, имхо, сразу нужна обработка ошибок, а потом уже всё остальное. Да, ошибся, но в прошлом коменте вроде пояснил, что к чему.
Так, надеюсь, понятно? ;)
Так, надеюсь, понятно? ;)
0
Например, мне проще выносить негатив в if, а обработку в else.
Наверное это как наполовину полный / пустой стакан. Интересно психологи думали об этом?
+2
int a = 0;
if( a ) что-то-там
Насколько я знаю, с expression внутри if происхдит неприятность — он evaluates в true или false. И, опять же, насколько я помню, char, short, int и __int64 если ==0 то evaluates в false, в противном случае в true.
float a = 0.0
if( a ) что-то-там
Так делать нельзя не потому что «все биты 0», а потому что float по стандарту не гарантирует что то, что мы туда положили будет 100% соответствовать тому, что изъяли. Из-за внутреннего представления: 1.0 / 2.0 может получиться 0.49999999999 :). Это тоже написано в стандарте.
В соатльном согласен, спасибо за статью.
BTW, еще говорят что:
читатеся лучше, чем
Но лично я не уверен.
if( a ) что-то-там
Насколько я знаю, с expression внутри if происхдит неприятность — он evaluates в true или false. И, опять же, насколько я помню, char, short, int и __int64 если ==0 то evaluates в false, в противном случае в true.
float a = 0.0
if( a ) что-то-там
Так делать нельзя не потому что «все биты 0», а потому что float по стандарту не гарантирует что то, что мы туда положили будет 100% соответствовать тому, что изъяли. Из-за внутреннего представления: 1.0 / 2.0 может получиться 0.49999999999 :). Это тоже написано в стандарте.
В соатльном согласен, спасибо за статью.
BTW, еще говорят что:
if( что-то-длинное && что-то длинное && что-то длинное )
читатеся лучше, чем
if( что-то-длинное && что-то-длинное && что-то-длинное )
Но лично я не уверен.
+1
Самый первый комментарий, процитирую:
«Тем не менее стандарт гарантирует, что при приведении float(0) или int(0) к bool мы получим false. „
«Тем не менее стандарт гарантирует, что при приведении float(0) или int(0) к bool мы получим false. „
+1
Да, я читал. Здесь уточнил, в каком именно месте и как он это гарантирует :). BTW, float( 0.0 ) только в том случае если мы только что положили 0.0 и не делали резких движений. Если 0 там подрозумевается как результат математической операции — то может не срастись :).
0
Об этом тоже были комментарии habrahabr.ru/blogs/cpp/61323/#comment_1680312
0
[offtopic]вот здесь бы понадобилась идея о плюсовании части комментария[/offtopic]
согласен со второй частью про «что-то-длинное»
согласен со второй частью про «что-то-длинное»
0
!errorFlag наверное имелось ввиду errorFlag
0
еще бы стоило посоветовать почитать Code Complete глава 31 (а лучше всю книгу)
0
// СОВСЕМ ПЛОХО
if (cond()) act();
else err();
я обычно в таких случаях пишу
if (cond()) act(); else err();
-5
Разницы с приведенным кодом почти нет. Плохость кода в примере не только в том, что он плохо читается как есть, а в основном в том, что его неудобно расширять. Добавляя код прийдется не забыть правильно расставить фигурные скобки и перенести на новую строку act(); или err(); — больше работы и диффы сложнее смотреть.
0
cond()? act(): err();
+4
коротко и однозначно
-1
особенно это удобно отлаживать, ага.
+2
Задача проследить путь выполнения программы в данном месте не представляет никакой трудности ни в одном из известных мне дебагеров. К тому же такая запись обычна применима в том случае, когда условие действительно простое, и если надо прервать выполнение если это условие ложно то можно использовать conditional breakpoints. Ах да, вариант переписать это в if else когда это действительно надо для отладки никто не отменял.
Да, я предпочту переписать через месяц пару таких простых кусков кода с добавлением подробного логирования, чем получить кашу из if else с кучей уровней вложенности.
Да, я предпочту переписать через месяц пару таких простых кусков кода с добавлением подробного логирования, чем получить кашу из if else с кучей уровней вложенности.
+4
Я считаю, что фигурные скобки надо ставить всегда.
А запись
else
bazzz();
ещё хуже, чем
else bazzz();
Как-то долго втыкал в кусок кода примерно следующего вида (линия между строк важна):
if(somethin)
a();
b();
c();
Долго не мог понять, почему выполняется b(), а a() при этом не отрабатывает.
А запись
else
bazzz();
ещё хуже, чем
else bazzz();
Как-то долго втыкал в кусок кода примерно следующего вида (линия между строк важна):
if(somethin)
a();
b();
c();
Долго не мог понять, почему выполняется b(), а a() при этом не отрабатывает.
0
По моему
if (expr)
{
//do something
}
else
{
//do another work
}
логичнее и смотриться лучше. Зачем скобки ставить на уровень if-else, это книжная запись чтобы экономить место. У нас же места навалом.
if (expr)
{
//do something
}
else
{
//do another work
}
логичнее и смотриться лучше. Зачем скобки ставить на уровень if-else, это книжная запись чтобы экономить место. У нас же места навалом.
+1
То же самое хотел написать =) Только еще отступов добавить внутри блоков.
Когда много вложенных фигурных скобок их очень легко цеплять взглядом, если открывающая и закрывающая на одной вертикали.
Когда много вложенных фигурных скобок их очень легко цеплять взглядом, если открывающая и закрывающая на одной вертикали.
0
Скобки ставятся на уровне if и else, чтобы подчеркнуть, что последующий код неразрывно связан с данным if или else (java-style). Если ставить скобки на новой строке, то if и код после него выглядят как независимые блоки(C#-style). То же касается объявления методов/функций.
+1
«Независимые» вы можете отодвинуть пустой строкой, или парой таких строк. Да и блог все-таки про c++.
«Неразрывно связанный» код для меня читается хуже.
«Неразрывно связанный» код для меня читается хуже.
0
каким же образом язык c#, появившийся много позже, чем c++ у нас уже заимел свою нотацию устаканненую? всегда пишу скобки на следущей строке, при чем тут c#, если я его открывал для ознакомления только?
0
Терпеть не могу такое написание. И не понимаю почему оно логичнее и не могу сказать, что оно смотрится лучше. И экран у меня ограничен по высоте, а хочется видеть побольше кода на экране:(
+2
Небольшая идея по улучшению кода, не относящаяся к статье.
При определении, находится ли число в некотором интервале, начало интервала, число и конец интервала лучше записывать в порядке их расположения на числовой оси.
Было:
bool isInside = figureX > leftLimit && figureX < rightLimit;
Стало:
bool isInside = leftLimit < figureX && figureX < rightLimit;
При определении, находится ли число в некотором интервале, начало интервала, число и конец интервала лучше записывать в порядке их расположения на числовой оси.
Было:
bool isInside = figureX > leftLimit && figureX < rightLimit;
Стало:
bool isInside = leftLimit < figureX && figureX < rightLimit;
+4
Это сбережёт процессорное время, память… в общем всё, что так дорого каждому человеку, исповедующему гуманистические идеалы :-)
Это вас кто-то обманул. Локальные переменные живут в стеке. Завести такой объект — одна инструкция: добавить размер объекта к esp.
0
Ну, если создание объекта занимает много времени, то сбережет в тех случаях, когда мы не попадаем в блок. Ну и вообще это хорошая практика — объявлять переменные непосредственно перед их использованием.
+4
Но широко распространенные компиляторы, типа gcc или msvc выделяют кадр стека один раз при входе в функцию и не меняют esp/ebp ходя по блокам внутри неё.
Кроме того, вызов конструктора и деструктора будет весить наверно больше, чем изменение размера кадра стека.
Кроме того, вызов конструктора и деструктора будет весить наверно больше, чем изменение размера кадра стека.
0
Нет ли здесь противоречия:
и
в том смысле, что переменные isInside && isGreen нужны только для проверки условия…
Хотя согласен, при отладке breakpoint + evaluate на if
выполнит someCheck, а на
А скажите, вот так форматировать код:
// ПЛОХО SomeClass p; // нужен только в блоке if (x == y) { p.moveTo(x, y); p.logResultsOfMovement(); }
и
// ОЧЕНЬ МИЛО bool isInside = figureX > leftLimit && figureX < fightLimit; bool isGreen = figureColor == GREEN; if (isInside && isGreen) { }
в том смысле, что переменные isInside && isGreen нужны только для проверки условия…
Хотя согласен, при отладке breakpoint + evaluate на if
if(someCheck()) { }
выполнит someCheck, а на
bool isGreen = someCheck(); if(isGreen) { }нет, что может быть важно, если someCheck возвращает другой результат при повторном вызове.
А скажите, вот так форматировать код:
if (a == b) { foo(); } else { bar(); }неприлично? Никак не могу привыкнуть писать «по стандарту», т.е. скобку сразу после if…
0
Вы попробуйте «по стандарту» делать — когда будете разбираться в программе — это упростит понимание. Главное — в одну кашу не пишите.
Всё дело в том, что
Всё дело в том, что
0
if (a == b){
foo();
}else{
bar();
}
1) выглядит компактнее
2) конец if-else ловится хорошо
foo();
}else{
bar();
}
1) выглядит компактнее
2) конец if-else ловится хорошо
+1
>>// ПЛОХО?
>>if (x == 1)
>>а
>>// ХОРОШО?
>>if (1 == x)
Нет, не хорошо. Есть ведь ещё перегрузка операторов и неявное преобразование из типа. Писать надо так как наиболее понятно. Думать о том, что может быть ошибка и из-за этого делать уродский код не стоит. В противном случае весь код окажется уродским и непонятным.
>>if (x == 1)
>>а
>>// ХОРОШО?
>>if (1 == x)
Нет, не хорошо. Есть ведь ещё перегрузка операторов и неявное преобразование из типа. Писать надо так как наиболее понятно. Думать о том, что может быть ошибка и из-за этого делать уродский код не стоит. В противном случае весь код окажется уродским и непонятным.
+2
В чем проблема с оператором совсем непонятно. Неужели сложно сделать
bool operator ==(const A& a, const B& b) { // Implementation } bool operator==(const B& b, const A& a) { return a == b; }
+2
Эти примеры не о том. Они созданы для использования операторов вне классов. К тому же представим, что типов преобразования не два A и B, а больше. С каждым вот таким использованием количество методов будет расти в геометрической прогрессии. Между прочим твои примеры как раз и показывают как делать не надо, тема называется «конструкторы и преобразования». Вот условно назову некий оператор #
1.operator#(x); // ошибка
И моё высказывание относилось вовсе не к тому, как её преодолеть. А именно к тому, что не нужно писать уродский код полагаясь на особенности некой реализации. Реализация в конце концов может оказаться совсем другой.
1.operator#(x); // ошибка
И моё высказывание относилось вовсе не к тому, как её преодолеть. А именно к тому, что не нужно писать уродский код полагаясь на особенности некой реализации. Реализация в конце концов может оказаться совсем другой.
0
Если вы сравниваете экземпляр класса A с экземпляром класса B, в большинстве случаев у вас будет определен либо конструктор
A::A(const B&)
либо A::operator B()
. В первом случае вам нужен bool operator==(const A&, const A&)
, во втором bool operator==(const B&, const B&)
, которые и так будут реализованы.0
На мой взгляд не важно как именно расставлены скобки и {}. Важно чтобы стиль был один и тот же во всем проекте. И все разработчики придерживались этого стиля.
+3
Почитайте Макконела «Совершенный код». Там все это рассматривается лучше, подробнее, понятнее и интереснее.
+3
Извините, придираюсь :)
bool dataReaded = readDdata(fileName);
не readed, а read…
глагол неправильный…
зы: сам недавно узнал что не payed, a paid :D
Статья каррошая, я очень трогательно отношусь к хорошему визуальному восприятию кода
bool dataReaded = readDdata(fileName);
не readed, а read…
глагол неправильный…
зы: сам недавно узнал что не payed, a paid :D
Статья каррошая, я очень трогательно отношусь к хорошему визуальному восприятию кода
-1
// ПЛОХО
SomeClass p; // нужен только в блоке
if (x == y) {
p.moveTo(x, y);
p.logResultsOfMovement();
}
// ХОРОШО
if (x == y) {
SomeClass p; // нужен только в блоке
p.moveTo(x, y);
p.logResultsOfMovement();
}
Это сбережёт процессорное время, память… в общем всё, что так дорого каждому человеку, исповедующему гуманистические идеалы :-)
Ну не правда. Возьмите этот код. Отключите оптимизацию, откомпелируйте… потом возьмем дизасемблер… и посмотрим что получилось. Так вот. Даже без оптимизации, компилятор создает одинаковый код. :)
(я беру компилятор от MS)
Если же включить функцию оптимизации, то код красиво так сложится в разы… и там вы уже даже с трудом обнаружите иницилизацию класса.
Остальные примеры исследовать с помощью написанием тестовых прог и их исследованием не стал. :)
P.S.
ДРугое дело, что код получается более правильный, но вот с точки зрения компилятора, без разницы.
SomeClass p; // нужен только в блоке
if (x == y) {
p.moveTo(x, y);
p.logResultsOfMovement();
}
// ХОРОШО
if (x == y) {
SomeClass p; // нужен только в блоке
p.moveTo(x, y);
p.logResultsOfMovement();
}
Это сбережёт процессорное время, память… в общем всё, что так дорого каждому человеку, исповедующему гуманистические идеалы :-)
Ну не правда. Возьмите этот код. Отключите оптимизацию, откомпелируйте… потом возьмем дизасемблер… и посмотрим что получилось. Так вот. Даже без оптимизации, компилятор создает одинаковый код. :)
(я беру компилятор от MS)
Если же включить функцию оптимизации, то код красиво так сложится в разы… и там вы уже даже с трудом обнаружите иницилизацию класса.
Остальные примеры исследовать с помощью написанием тестовых прог и их исследованием не стал. :)
P.S.
ДРугое дело, что код получается более правильный, но вот с точки зрения компилятора, без разницы.
+1
Я уже писал выше. Если конструктор SomeClass тяжёлый, а ситуация, когда x == y случается редко, в производительности вы выиграете заметно.
0
тесты есть? :)
0
Код тут
Paul@paulcomp /cygdrive/d/src/cpp/benchmarks $ g++-4 --version g++-4 (GCC) 4.3.2 20080827 (alpha-testing) 1 Copyright © 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Paul@paulcomp /cygdrive/d/src/cpp/benchmarks $ g++-4 -O2 -o test test.cpp Paul@paulcomp /cygdrive/d/src/cpp/benchmarks $ time ./test.exe 1 real 0m6.816s user 0m6.625s sys 0m0.015s Paul@paulcomp /cygdrive/d/src/cpp/benchmarks $ time ./test.exe real 0m0.733s user 0m0.656s sys 0m0.015s
0
В примере условие 0 == i % 10 эмулирует ситуацию, когда x == y случается в 9 раз реже, чем x != y.
0
Всё зависит от контекста, иногда «плохие» приёмы очень выразительны. Ничего нет хуже для понимания, чем 20 строк «правильно» оформленного пятистрочного алгоритма. Тут главное без фанатизма.
+1
интересная заморочка.
0
В общем, очень много спорных практик.
for(;;), проверки на ошибки и т.п.
Вообще говоря, я склонен все проверки делать как раз наоборот (precondition, assertion, postcondition — все проверяют на ошибки, а не на нормальный ход, равно как и CodeContract в C#).
for(;;), проверки на ошибки и т.п.
Вообще говоря, я склонен все проверки делать как раз наоборот (precondition, assertion, postcondition — все проверяют на ошибки, а не на нормальный ход, равно как и CodeContract в C#).
0
Вот если бы вы, уважаемый автор, хотя бы изредка читали хорошие книжки по программированию…
-2
Так я готов! Посоветуйте! (Кстати, тогда от вашего комментария будет польза и мне и людям.)
0
> Так я готов! Посоветуйте!
«Космонавтом быть хочу, пусть меня научат». Так получается?
> Кстати, тогда от вашего комментария будет польза и мне и людям.
Почему эти самые люди сами не могут себе помочь? Никто же не придет их спасать. Первый шаг сделать очень просто. :)
Вопрос о расставлении фигурных скобок очень важен, лол.
> Создавайте переменные только при необходимости
Это верно.
> Используйте преимущества С++. Если переменная нужна только в блоке, то и создавайте её только в блоке. Это сбережёт процессорное время, память… в общем всё, что так дорого каждому человеку, исповедующему гуманистические идеалы :-)
«Преимущество», ололо. Определение переменной вначале блока или же «когда нужно» сбережет только время читателя. Тут есть ньюансы, связанные с тем, что определение переменной может содержать побочные эффекты.
> В качестве условия следует использовать только логические величины. Это же, кстати относится и к циклам
Это следует из того, что if представляет собой именно что условие, и из соображений типобезопасности (type safety) неявного преобразования и прочей хреноты нужно избегать. Впрочем, к реальным программам на Си/Си++ это не относится, потому что языки такие. :)
> Если логическое выражение состоит из нескольких частей, то самой плохой практикой является запись их всех в кучу. Можно ли быстро понять, что тут написано?
Конечно же можно. У операций по конвенции определен приоритет, ассоциативность, коммутативность и проч., которые позволяет читателю понять, что тут написано без лишних телодвижений.
Проще говоря,
> if (figureX > leftLimit && figureX < fightLimit && figureColor == GREEN)
То же самое, что и
> if ((figureX > leftLimit) && (figureX < fightLimit) && (figureColor == GREEN))
Потому что у операций сравнения приоритет выше, чем у логического «и». К тому же логическое «и» ассоциативно и коммутативно, поэтому некоторые скобки можно опустить (что мы и сделали), а сами подвыражения можно писать в любом порядке.
> Выражения лучше выносить из условий
Если выражение сложное (отвлекает от условия), тогда его однозначно следует вынести куда подальше.
> Такую программу на много проще читать, и кроме того, переменные isInside и isGreen могут пригодиться в дальнейшем.
Вот когда пригодятся, тогда и вынесем. :) YAGNI.
> По уже изложенным причинам, в логических выражениях лучше не выполнять присвоения:
Это были не причины, а сотрясение воздуха. Настоящей причиной являются побочные эффекты, из-за которых выражение может получить новые интересные трактовки. :)
> Ну и, конечно, «каждому выражению своя строка!».
Налицо явная путаница в терминах «выражение» (expression) и «утверждение» (statement).
> то вы можете не бояться опечатать и написать "=" вместо "==".
Ни разу не попадался на эту ошибку. Счастливчик. :)
Почитайте Вирта (Алгоритмы и Структуры данных), SICP, HTDP, etc. И не пишите таких дезинформирующих статей.
«Космонавтом быть хочу, пусть меня научат». Так получается?
> Кстати, тогда от вашего комментария будет польза и мне и людям.
Почему эти самые люди сами не могут себе помочь? Никто же не придет их спасать. Первый шаг сделать очень просто. :)
Вопрос о расставлении фигурных скобок очень важен, лол.
> Создавайте переменные только при необходимости
Это верно.
> Используйте преимущества С++. Если переменная нужна только в блоке, то и создавайте её только в блоке. Это сбережёт процессорное время, память… в общем всё, что так дорого каждому человеку, исповедующему гуманистические идеалы :-)
«Преимущество», ололо. Определение переменной вначале блока или же «когда нужно» сбережет только время читателя. Тут есть ньюансы, связанные с тем, что определение переменной может содержать побочные эффекты.
> В качестве условия следует использовать только логические величины. Это же, кстати относится и к циклам
Это следует из того, что if представляет собой именно что условие, и из соображений типобезопасности (type safety) неявного преобразования и прочей хреноты нужно избегать. Впрочем, к реальным программам на Си/Си++ это не относится, потому что языки такие. :)
> Если логическое выражение состоит из нескольких частей, то самой плохой практикой является запись их всех в кучу. Можно ли быстро понять, что тут написано?
Конечно же можно. У операций по конвенции определен приоритет, ассоциативность, коммутативность и проч., которые позволяет читателю понять, что тут написано без лишних телодвижений.
Проще говоря,
> if (figureX > leftLimit && figureX < fightLimit && figureColor == GREEN)
То же самое, что и
> if ((figureX > leftLimit) && (figureX < fightLimit) && (figureColor == GREEN))
Потому что у операций сравнения приоритет выше, чем у логического «и». К тому же логическое «и» ассоциативно и коммутативно, поэтому некоторые скобки можно опустить (что мы и сделали), а сами подвыражения можно писать в любом порядке.
> Выражения лучше выносить из условий
Если выражение сложное (отвлекает от условия), тогда его однозначно следует вынести куда подальше.
> Такую программу на много проще читать, и кроме того, переменные isInside и isGreen могут пригодиться в дальнейшем.
Вот когда пригодятся, тогда и вынесем. :) YAGNI.
> По уже изложенным причинам, в логических выражениях лучше не выполнять присвоения:
Это были не причины, а сотрясение воздуха. Настоящей причиной являются побочные эффекты, из-за которых выражение может получить новые интересные трактовки. :)
> Ну и, конечно, «каждому выражению своя строка!».
Налицо явная путаница в терминах «выражение» (expression) и «утверждение» (statement).
> то вы можете не бояться опечатать и написать "=" вместо "==".
Ни разу не попадался на эту ошибку. Счастливчик. :)
Почитайте Вирта (Алгоритмы и Структуры данных), SICP, HTDP, etc. И не пишите таких дезинформирующих статей.
-2
> «Космонавтом быть хочу, пусть меня научат». Так получается?
И снова тоже самое — если вы видите в этом что-то постыдное (я не вижу), то предложите свой вариант (а то как-то неконструктивно). Или вы сторонник точки зрения "уже хаскель знаю и никем быть не хочу и учиться тоже фтопку"? Я же не прошу вас меня учить, я спрашиваю про книги.
> Почему эти самые люди сами не могут себе помочь?
> Никто же не придет их спасать. Первый шаг сделать очень просто. :)
Откуда вы это взяли? «не могут», «не придет», «Первый шаг»? Вы прям экстрасенс какой-то :-) И шаги уже посчитали, и возможности всех оценили… не много на себя берёте? (извините, просто интересуюсь :-))
Ну а всё остальное конструктивно (почти везде). Спасибо. Спорить не буду, на что-то я уже тут отвечал, на что-то отвечали другие, что-то бесспорно…
Вирта читал. Не очень понимаю, как эта книга относится к теме статьи. Тут народ советовал «Совершенный код» С. Макконнелла — вот это по теме было. Статья-то не про алгоритмы и не про структуры.
И снова тоже самое — если вы видите в этом что-то постыдное (я не вижу), то предложите свой вариант (а то как-то неконструктивно). Или вы сторонник точки зрения "
> Почему эти самые люди сами не могут себе помочь?
> Никто же не придет их спасать. Первый шаг сделать очень просто. :)
Откуда вы это взяли? «не могут», «не придет», «Первый шаг»? Вы прям экстрасенс какой-то :-) И шаги уже посчитали, и возможности всех оценили… не много на себя берёте? (извините, просто интересуюсь :-))
Ну а всё остальное конструктивно (почти везде). Спасибо. Спорить не буду, на что-то я уже тут отвечал, на что-то отвечали другие, что-то бесспорно…
Вирта читал. Не очень понимаю, как эта книга относится к теме статьи. Тут народ советовал «Совершенный код» С. Макконнелла — вот это по теме было. Статья-то не про алгоритмы и не про структуры.
0
> И снова тоже самое — если вы видите в этом что-то постыдное (я не вижу)
Книжки искать долго что ли? Чай гуглом все умеют пользоваться.
> Или вы сторонник точки зрения «уже хаскель знаю и никем быть не хочу и учиться тоже фтопку»? Я же не прошу вас меня учить, я спрашиваю про книги.
Нет, я сторонник высказывания «век живи, век учись, — помрешь все равно дураком». ;)
> Ну а всё остальное конструктивно (почти везде). Спасибо. Спорить не буду, на что-то я уже тут отвечал, на что-то отвечали другие, что-то бесспорно…
«Почти везде» — где именно неконструктивно? Там нету ни одного наезда на Си/Си++.
> Вирта читал. Не очень понимаю, как эта книга относится к теме статьи. Тут народ советовал «Совершенный код» С. Макконнелла — вот это по теме было. Статья-то не про алгоритмы и не про структуры.
У Вирта хорошо написано о структурном программировании. В статье говорится о том, как улучшить структуру кода (должно говориться, вообще-то).
«Совершенный код» не читал, но исправлю при первой же возможности. Главное, чтобы не оказалось как с Г.Бучем и его ООП. :)
Книжки искать долго что ли? Чай гуглом все умеют пользоваться.
> Или вы сторонник точки зрения «уже хаскель знаю и никем быть не хочу и учиться тоже фтопку»? Я же не прошу вас меня учить, я спрашиваю про книги.
Нет, я сторонник высказывания «век живи, век учись, — помрешь все равно дураком». ;)
> Ну а всё остальное конструктивно (почти везде). Спасибо. Спорить не буду, на что-то я уже тут отвечал, на что-то отвечали другие, что-то бесспорно…
«Почти везде» — где именно неконструктивно? Там нету ни одного наезда на Си/Си++.
> Вирта читал. Не очень понимаю, как эта книга относится к теме статьи. Тут народ советовал «Совершенный код» С. Макконнелла — вот это по теме было. Статья-то не про алгоритмы и не про структуры.
У Вирта хорошо написано о структурном программировании. В статье говорится о том, как улучшить структуру кода (должно говориться, вообще-то).
«Совершенный код» не читал, но исправлю при первой же возможности. Главное, чтобы не оказалось как с Г.Бучем и его ООП. :)
0
При поиске книжек гугл человека никак не может заменить. Хороших книжек очень мало (по сравнению с вообще книжками :-)). Тут как раз интересно мнение опытного человека.
Почему вы читаете «неконструктивно» == «наезд»? ,-) Я отношу к неконструктивному всё, что не относится к статье. По разным причинам. Хотя бы из-за субъективности («Ни разу не попадался на эту ошибку.»; статья-то не про вас; и даже не про меня :-))
Ну и статья не о структурном программировании, как таковом. Это просто мысли про if. Я хотел бы сам про это почитать, но никто не написал и я запустил эту дискуссию.
А совершенный код, я вам (именно вам!) очень советую! И ваше мнение мне было бы очень интересно! С одной стороны, книжка очень толковая. (Очень!) С другой стороны, в ней есть наезды на рекурсию, которые даже меня на столько покоробили, что я написал про это заметку :-) Вы, как любитель рекурсии (и я с вами солидарен полностью) наверняка испытаете сильные эмоции, читая этот труд :-) По крайней мере, Макконнелл пишет прямым текстом, что вас бы он уволил не задумываясь :-)
Почему вы читаете «неконструктивно» == «наезд»? ,-) Я отношу к неконструктивному всё, что не относится к статье. По разным причинам. Хотя бы из-за субъективности («Ни разу не попадался на эту ошибку.»; статья-то не про вас; и даже не про меня :-))
Ну и статья не о структурном программировании, как таковом. Это просто мысли про if. Я хотел бы сам про это почитать, но никто не написал и я запустил эту дискуссию.
А совершенный код, я вам (именно вам!) очень советую! И ваше мнение мне было бы очень интересно! С одной стороны, книжка очень толковая. (Очень!) С другой стороны, в ней есть наезды на рекурсию, которые даже меня на столько покоробили, что я написал про это заметку :-) Вы, как любитель рекурсии (и я с вами солидарен полностью) наверняка испытаете сильные эмоции, читая этот труд :-) По крайней мере, Макконнелл пишет прямым текстом, что вас бы он уволил не задумываясь :-)
0
> Почему вы читаете «неконструктивно» == «наезд»? ,-)
Стереотипы. :)
> Я отношу к неконструктивному всё, что не относится к статье. По разным причинам. Хотя бы из-за субъективности («Ни разу не попадался на эту ошибку.»; статья-то не про вас; и даже не про меня :-))
Да, субъективно очень. Не удержался.
> А совершенный код, я вам (именно вам!) очень советую! И ваше мнение мне было бы очень интересно! С одной стороны, книжка очень толковая. (Очень!) С другой стороны, в ней есть наезды на рекурсию, которые даже меня на столько покоробили, что я написал про это заметку :-) Вы, как любитель рекурсии (и я с вами солидарен полностью) наверняка испытаете сильные эмоции, читая этот труд :-) По крайней мере, Макконнелл пишет прямым текстом, что вас бы он уволил не задумываясь :-)
Ну точно надо почитать. :)
Стереотипы. :)
> Я отношу к неконструктивному всё, что не относится к статье. По разным причинам. Хотя бы из-за субъективности («Ни разу не попадался на эту ошибку.»; статья-то не про вас; и даже не про меня :-))
Да, субъективно очень. Не удержался.
> А совершенный код, я вам (именно вам!) очень советую! И ваше мнение мне было бы очень интересно! С одной стороны, книжка очень толковая. (Очень!) С другой стороны, в ней есть наезды на рекурсию, которые даже меня на столько покоробили, что я написал про это заметку :-) Вы, как любитель рекурсии (и я с вами солидарен полностью) наверняка испытаете сильные эмоции, читая этот труд :-) По крайней мере, Макконнелл пишет прямым текстом, что вас бы он уволил не задумываясь :-)
Ну точно надо почитать. :)
0
Спасибо, сейчас активно изучаю Java и статья пришлась впору :)
Прошу не минусуйте, почти все моменты с конструкторами схожи в этих языках.
P.S. раньше я кодил на одном из не очень известных языках скриптинга, и там постоянно были проверки такого типа — (и избежать их было нельзя, в силу ограниченности языка)
Obj = <src.act>
if (<Serv.Uid.<Obj.Tag0.linkToAnotherObject>.tag0.someInteger> == <Obj.SomeAnotherInteger>)
и даже больше и страшнее. Слава богу, что появилась возможность и желание изучать нормальные логичные языки программирования :)
Прошу не минусуйте, почти все моменты с конструкторами схожи в этих языках.
P.S. раньше я кодил на одном из не очень известных языках скриптинга, и там постоянно были проверки такого типа — (и избежать их было нельзя, в силу ограниченности языка)
Obj = <src.act>
if (<Serv.Uid.<Obj.Tag0.linkToAnotherObject>.tag0.someInteger> == <Obj.SomeAnotherInteger>)
и даже больше и страшнее. Слава богу, что появилась возможность и желание изучать нормальные логичные языки программирования :)
0
>Можно ли быстро понять, что тут написано?
>
>// ПЛОХО
>if (figureX > leftLimit && figureX < fightLimit && figureColor == GREEN)
>
>Подсветка, конечно, помогла бы, но и без подсветки следующее выражение читается на много проще:
>
>// ХОРОШО
>if (figureX > leftLimit &&
> figureX < fightLimit &&
> figureColor == GREEN)
Мне кажется, единственный надежный способ быстро понять, что здесь написано — вынести выражение в отдельную функцию и дать ей говорящее имя. Всё равно остается непонятно, что имелось в виду и не ошибся ли автор логического выражения или тот кто это выражение недавно правил.
if (isFigureTarget(figureX, figureColor))
>
>// ПЛОХО
>if (figureX > leftLimit && figureX < fightLimit && figureColor == GREEN)
>
>Подсветка, конечно, помогла бы, но и без подсветки следующее выражение читается на много проще:
>
>// ХОРОШО
>if (figureX > leftLimit &&
> figureX < fightLimit &&
> figureColor == GREEN)
Мне кажется, единственный надежный способ быстро понять, что здесь написано — вынести выражение в отдельную функцию и дать ей говорящее имя. Всё равно остается непонятно, что имелось в виду и не ошибся ли автор логического выражения или тот кто это выражение недавно правил.
if (isFigureTarget(figureX, figureColor))
0
Вынесение в отдельные функции — это всегда хорошо. Но тут есть два риска.
1. Во многих случаях функции могут неоправданно расплодиться.
2. А внутри функции что будет? Такое же непонятное выражение? Название, конечно прояснить его смысл, но вот чтение (поиск ошибок) не облегчится.
1. Во многих случаях функции могут неоправданно расплодиться.
2. А внутри функции что будет? Такое же непонятное выражение? Название, конечно прояснить его смысл, но вот чтение (поиск ошибок) не облегчится.
0
Забавно, ссылка на ГеоСофт — когда-то и сам активно пользовался тем документом, а нашёл его в то время, когда каталоги ссылок были популярнее поисковиков.
Кто-нибудь знает, кто его составил? Что это за ГеоСофт такой?
Кто-нибудь знает, кто его составил? Что это за ГеоСофт такой?
0
Sign up to leave a comment.
Всё ли вы знаете про if?