Pull to refresh

Comments 57

А вы в хромиум багрепорты\патчи отправили? :)
Автор молодец! Буду теперь разбирать статью.
В лиспе можно работать с opencv? Там есть какие-нибудь библиотеки для обработки изображений и распознавания образов?
В С++ поддержка библиотек для обработки изображений и распознавания образов лучше, чем в лиспе.
Но если охота С++ и лисп использовать, то можно попробовать intelib
Только думал стоит ли чаще использовать скобки в "?:", т.к. зачастую их игнорируют и пишут выражения как можно сжато. И вот очевидные плюсы скобок!
Я зашел на сайт Newton Dynamics чтобы найти игру с танком на картинке, но в Showcase нету ничего про танки
Где вы ее взяли?
Это демонстрация работы движка. Ролики можно посмотреть здесь.
Скобки вообще редко вредят читабельности кода. Нас учили при малейшем сомнении в приоритетах операторов ставить скобки :)

У Страуструпа в самом начале сказано, что С++ одновременно и любят и ненавидят за возможность конструкций типа --*p++.
Любопытно, что в Java из-за более строгой системы типов такой проблемы не возникает:

Интересно, распознавание таких вещей в плюсах на уровне компилятора (выдача варнинга) ничему не противоречит? GCC -Wall -Wextra молчит на такую строчку.
А на что здесь ругаться компилятору? Вполне законная конструкция. Это удел статических анализаторов, которые занимаются некой эвристикой.
Неиспользуемая переменная тоже вполне законна, но компилятор выдаёт варнинг :-)
Что такое неиспользуемая переменная это просто и понятно. Диагностика ошибки с "?:" не столь очевидна и компиляторы не затачивают на подобную сложную логику анализа. Вот описание диагностики V502. Это я просто скопировал комментарий из кода PVS-Studio:
/*
Общее правило N2.
Генерирует предупреждение V502.
(Сам придумал (Андрей Карпов). Аналогов не видел.)
Выражение с оператором '?:' считается опасным, если слева от него последняя переменная имеет
тип bool или BOOL и при этом слева от нее есть оператор с приоритетом выше чем у '?:'.
А именно опасным считаем: ||, &&, |, ......, /, *.

Пример:
int a;
bool b;
int c = a + b ? 0 : 1;

Исключения:
1) Еще левее объект также имеет тип bool или BOOL.
2) Оператором слева является || или &&, и при этом левее расположен объект является
указателем или указатель это то, что возвращает оператор ?:.
Это кажется странным, но подобные конструкции действительно неопасны, так как
невозможно компилировать:
"int = ptr && (bool ? int : int)"
"ptr = ptr && (bool ? ptr : ptr)"
"bool = (int && bool) ? ptr : ptr"
Пример кода для исключения:
Tobj *p;
x = p && a==b ? p->foo() : 0;
*/

Спасибо за детальное объяснение правила. Интересно, у вас все комментарии на русском? :-)
Да. А зачем их делать на английском? :-)
Просто спросил, холивар не подразумевался :-)
ну вдруг вы вырастете и вас купит какаянибудь крупная мультинациональная контора?
Уверен, что комментарии на русском языке не станут в этом случае препятствием :-)
На то, что boolean и int — разные вещи (в зависимости от языка).
В плюсах можно очень легко на грабли наступить из-за того, что в качестве boolean может выступать что угодно. Например, недавно наткнулся на такой код:
if (obj.is_null) { ... }
Вроде бы всё хорошо, вот только в данном случае это должна была быть функция is_null(), и указатель на функцию автоматом привёлся к boolean
Если в лоб предупреждать, что в выражении тип bool смешивается с типом int, большинство программистов это выключат. Слишком много подобного кода. По крайней мере я очень много видел. Что стоят только проверки вида:
bool x;
if (x & 1 > 0)
Да, так пишут. Вот только что рассматривал подобный образец искусства. Это работает и никто не кинется перелопачивать мегабайты кода в целях эстетической красоты. :)
Нужны более сложные проверки. Описание подобной, я привел выше. В компиляторах по возможности стараются реализовывать более очевидные.
Ну так исходный коммент-то про Java, не про плюсы. Там нет этой «фичи».
Если в Java написать нечто подобное:

bool Z = X && (A == B) ? !A : !B;

то компилятор это съест, однако же подобная ошибка останется.
Верно. Но, согласитесь, пример довольно искусственный :-) Если A равно B, то обе ветки тернарного оператора тоже равны, поэтому выражение сводится к
bool Z = X && !B;
Можно, наверно, выдумать что-то более приближенное к реальности, но в своей практике я не припомню примеров, чтобы тернарный оператор требовался в чисто булевом выражении.
Соглашусь, да искусственный. Но он показывает, что строгая типизация не дает полной защиты от не правильной трактовки приоритетов операторов. Хотя очень помогает, особенно от ошибок типа:
if (a = b) { /* ... */ }

К сожалению в C++ из-за населения С такая типизация в принципе не возможна.
Кроме того, PVS-Studio на этот пример также промолчит :-)
Да. Иначе ложное срабатывание будет в 99% случаев, если не больше.
Хорошая статья. На сколько же граблей наступил, пока не дошёл до того-же самого.
А зачем реклама в тексте поста? (это не хабрахабровская)
Макросы плохи по множеству причин. Уж лучше тогда inline функцию сделать.
Например? (Нет, не буду утверждать, что макросы всем хороши, но интересен этот момент.) Чем плох этот макрос? Чем лучше аналогичный inline?
Конкретно этот — кажется ничем. А вообще почти всегда макрос, это усложнение отладки и т.д.
И многие другие тоже ничем. Поэтому я и не гнушаюсь пользоваться макросами. Умелое их применение позволяет сильно улучшить читабельность и гибкость кода. То же самое относится и к другим видам препроцессинга. У меня зачастую применяется ещё m4 и некоторые кастомные вещи.
Насчёт усложнения отладки — только при ошибках в макросах. Директива #line неспроста придумана.
Вот интересно, как различные системы code-assist с макросами дружат? Даже конкретно на этом примере. Определят ли они возвращаемый тип этого макроса, чтобы на этапе написания кода отследить несоответствие типов (скажем, результат cond() подаётся параметром в функцию)? Проверят ли, что тип второго и третьего аргумента должен совпадать? Выдадут ли всплывающую подсказку по типам аргументов cond()? Всё-таки в плане контроля типов шаблонированная inline-функция кажется надёжнее.
Контроль типов произведёт компилятор, если про него забудет программист. А если какая-то система «code assist» не умеет стандартный препроцессор — это плохая система.
И потом, какие шаблоны в C?
Пост вроде в блоге C++, в ветке комментариев C не упоминался, так что вопрос скорее «а при чём тут C?» :-) Сомневаюсь, что даже продвинутый code assist подскажет, что первым параметром cond должен идти булев аргумент, потому что явно в макросе это нигде не сказано (а в inline-функции будет сказано). Пусть знатоки плюсовых IDE подскажут. Контроль типов на этапе написания кода существенно ускоряет работу и освобождает голову для более важных вещей. У меня, к примеру, благодаря code assist, ошибки компиляции практически никогда не встречаются, экономя мне время на лишние запуски компиляции.
А, тогда извините, не тот пост комментирую. Я на C++ не пишу ;b
А к макросу — он int (или приводимый к нему), и это явно в макросе прописано, ибо ?:.
По поводу этого макроса, могу сказать, что скорее всего человеку, который будет читать этот код, придется смотреть определение этого макроса.
Практически всегда и везде беру все что можно в скобки.
Приоритеты операций знать конечно нужно, но не дай бог из-за глупой ошибки полезут рандомные трудноотлаживаемые баги… Лучше написать немного лишних скобок и получить гарантию, что операции будут выполняться в верном порядке.
А на каком основании анализатор выдает такое уверенное сообщение о том, что тернарный оператор используется не правильно? Возможно разработчик имел ввиду именно то, что написал.
Кстати, я подумал о том же, когда посмотрел на код Newton Game Dynamics к примеру.
На Newton Game Dynamics видно, что ошибка, потому что на bool умножение, а вот в хромиуме не понятно. Наверно стоило бы добавить слово «возможно» в текст сообщения.
Ну вот другой примерчик. ;) Не Chromium, но его составная часть (библиотека Sanitiser for OpenType). Здесь вообще условие всегда истинное получается:

// Copyright © 2011 The Chromium Authors.
// ...
bool version_2;

bool ots_gdef_parse(...)
{
...
const unsigned gdef_header_end = static_cast(8) +
gdef->version_2 ? static_cast(2) : static_cast(0);
...
}

Вы не поверите :) но сообщение анализатора начинается со слова «Возможно»:

Perhaps the '?:' operator works in a different way than it was expected.
Упс, не заметила, спаисбо. Мне показалось, что оно как-то слишком уж утвердительно выглядит.
Иногда он конечно и ошибается. Но очень подозрительно, например, что здесь bool умножается на float.
den = dgFloat32 (1.0e-24f) *
(den > dgFloat32 (0.0f)) ? dgFloat32 (1.0f) : dgFloat32 (-1.0f);

Очень сомневаюсь, что так и задумано. :)
С другими примерами аналогичная ситуация.
это лишь малая часть С++ айсберга
а в целом начало отличное.
Спасибо
Ха! Именно сегодня мне понадобилось создавать ссылки внутри функции (ранее использовал их лишь в качестве жёстких алиасов), и порадовался при этом тому, как оператор ?: классно подходит для их инициализации! :)
не смотря на то, что вы пиарите свою студию, статьи у вас интересные и почитать любо-дорого) спасибо
Что-то вас тут подвел хостинг картинок — грузятся совсем левые вещи…
Sign up to leave a comment.