Как стать автором
Обновить

Комментарии 26

«if(strcmp(s,r)), когда правильно if(strcmp(s,r)==0)» — почему правильно?
Потому что это два противоположных условия. Код внутри
if(strcmp(s,r))
выполняется, когда они не равны, а
if(strcmp(s,r)==0)
— когда равны.
Правильно потому что это два противоположных условия? Серьезно? Откуда вы знаете что этот код должен делать?
Под «правильно» здесь понимается best practice. Довольно часто встречается код
if(strcmp(s,r)) {
// когда равны
}

Или
if(!strcmp(s,r)) {
// когда не равны
}


Этих ошибок бы не было, если писать явно == 0
Вы все еще продолжаете видеть какие-то ошибки в абсолютно корректном коде, мне это странно
Не могли бы Вы пояснить, в чем собственно ошибка и почему нужно именно
if(strcmp(s,r) ==0 ), а не просто if(!strcmp(s,r)).
Человек может ошибиться и прочитать if(!strcmp(s,r)) как «если строки не равны». Best practice как раз и направлены на уменьшение количества таких потенциальных проблем.
В первом случае идет проверка на то, что первая строка больше второй. Во втором случае идет проверка на равенство строк.
Говорится о коварности неявного преобразования int в bool. Это может дать не тот результат, что хотелось бы получить.

Update: впрочем, ответ уже дали. Зависит, конечно, целиком и полностью от контекста применения. Но, наверное, удобнее читать будет, когда в явном виде будет указано возвращаемое значение. То есть, второй вариант.
Возможно автор хотел сказать что if (strcmp(s, r) == 0) наиболее часто использующийся случай для проверки равны ли строки. Я бы наверное оформил это таким образом
if (strcmp(s, r) ==0 ) — проверить равны ли строки
if (strcmp(s, r) !=0 ) — проверть не равны ли строки

А так да, говорить что if(strcmp(s,r)==0) неверно, неверно :)
Если программисту нужно совпадение строк, то правильным будет правое выражение, но по ошибке он может написать левое и получит результат с точностью до наоборот, условие будет верным, если строки не совпадают.
НЛО прилетело и опубликовало эту надпись здесь
Прям с языка снял. Автор поста как бы говорит «Зачем вам С++, смотрите там много сложных моментов, пишите лучше на С#»
Зачем эти тупые сравнения с С#, непонятно. Всё описанное является в большинстве своём обычным поведение С++ которое проходится по мере изучения. Почему не было расписано про подводные косяки использования лямбд например, когда замыкаешь значение по ссылке а потом выходишь из скоупа, или возврат ссылки или указатела на локальные переменные.
Да блин в С++ есть гораздо больше тонких мест, на которые действительно можно наткнутся, а в статье большинство примеров это притянутый за уши бред который практически никогда не встречается в реальности.
Согласен, что в C++ много еще более тонких моментов. Я описал базовые проблемы. Еще раз, никакой агитации за C# нет, хотелось показать, за счет чего весьма близкий язык является более надежным и удобным. Лично я считаю, что C++ программисту весьма полезно понимать как работают платформы .NET или Java. Большинство примеров не притянуто за уши, я натыкался на них в коде коллег (включая самого себя).
Эти базовые моменты никому не интересны, они описаны во всех учебниках (хотя сомневаюсь что хоть кто-то подозревает что перегрузка является опасной (sic!)).
По поводу коллег сочувствую. А по поводу агитации да простите, её там совсем не чувствуется чего это я. (С# является моим 3 любимым языком, но вот с++ для меня является гораздо более удобным, так что это субъективно)
Ну корни у меня самые, что ни на есть плюсовые, с 90х. С++ я люблю и пишу на нем постоянно уже десятки лет. Моя цель — обратить внимание на проблемные моменты программирования на С++, которые легко могут привести к ошибкам. Программисты должны помнить об этих проблемах, не терять бдительности и при необходимости принимать необходимые меры. Никакой агитации за C# нет, просто хотелось показать, за счет чего, весьма близкий язык является более надежным и удобным. В целом стиль отзыва выглядит сумбурным, если не сказать истеричным. Практически ничего по существу ответить нельзя, так как никакой существенной критики нет, сплошные вопли.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Не знаю, почему статью минусуют.
Вполне адекватно описаны пусть базовые, но все же нюансы языка. Указан к каждому пункту возможный путь борьбы с этими нюансами. Сравнение с C#, имхо, идет с точки зрения аналогии, а не рекомендации перейти на него. Не вижу причин для бомбежа.
Не вижу причин для написания подобной заметки, т.к. тут не с чем бороться.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Хочу еще раз обратить внимание, что никакой агитации за C# нет, просто хотелось показать, за счет чего, весьма близкий язык является более надежным и удобным. Сам я пишу на C++/C# где-то 50 на 50 уже много лет, и люблю оба языка. Считаю, что C++ программисту весьма полезно знать C# (ну на худой конец Java).
Нет. Это язык со статической типизацией, но она не строга ни в смысле гарантий, ни в смысле выразительности.

Статическая/динамическая типизация и строгая/нестрогая типизация это разные критерии классификации типизированных языков. Сильная типизация выделяется тем, что язык не позволяет смешивать в выражениях различные типы и не выполняет автоматические неявные преобразования. C++ спроектирован как язык со строгой типизацией, но с рядом послаблений в виде implicit conversions, из-за чего его чисто формально можно отнести к языкам с нестрогой типизацией. Вот статья на эту тему.
Так и не понял, что именно тут плохо. Какие-то общие слова, что можно делать ошибки. Так, наверное, можно вообще про любую языковую фичу написать в любом языке.

Программист может написать такие перегрузки, что потом будет пол дня думать, как они будут разрешатся в том или ином контексте. Я рекомендую так не делать. Потом перегруженные функции затрудняют анализ кода, особенно чужого, с помощью текстового поиска.
В C#, кстати, есть rvalue-ссылки и вообще move semantics?

Этого в C# нет.
То есть, если вы пишете управляющий ресурсом класс, то его, внезапно, надо сесть и писать. Нетривиальный вывод!

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

Я как раз и имел в виду производительность.
Не понял логики. А как же порядок объявления членов?

В C# при создании объекта сначала инициализируются все поля объекта (значениями, заданными при объявлении или по умолчанию), затем вызывается конструктор базового класса или перегруженный конструктор, если они указаны в списке инициализации, затем сам конструктор.
Только это всё же не совсем то. Начиная с C++11 статик-переменные уровня функций инициализируются потокобезопасно, что, конечно, хорошо, но ведёт к очевидной дополнительной плате на синхронизацию при каждом входе в такую функцию.

За все надо платить. Но в данном случае немного, такой вызов обычно происходит один раз.
Не использовать сырое new. 2018 год на дворе уже, ё-моё.

Конечно, new/delete должны быть максимально инкапсулированы. Но полностью избавится от них не реально. C++ программист должен четко знать, как с ними правильно работать.
Использовать make_unique и make_shared.

Помогает, но не всегда. Эти шаблоны не позволяют использовать пользовательские удалители, и в этом случае придется работать с сырыми указателями и надо знать, как правильно писать выражения без потенциальных утечек памяти.
Судя по общему тону до этого, считается, что это в C# сделано типа хорошо?

Тут я выразился не совсем точно. Описываю ситуацию более подробно. Пусть в C# у нас есть базовый класс и производный. При создании экземпляра производного класса сначала инициализируются все поля базового класса и затем все поля производного. Только после этого вызывается конструктор базового класса и потом конструктор производного. Пусть в базовом классе определена виртуальная функция и она переопределяется в производном. Если в конструктор базового вставить вызов этой виртуальной функции, то вызовется переопределенная, соответственно, для объекта у которого уже инициализированы поля, но еще не вызывался конструктор. Довольно забавно. Если четко понимать, как это работает, то можно использовать.
В C# программист тоже может сделать в unsafe-блоке какую-нибудь ерунду, разве нет?

Программист пишет unsafe-блоки на свой страх и риск. Почти все гарантии .NET отменяются.
Да и говорить о сборщике мусора как о спасении от «значительной части» проблем, как будто единственный существующий ресурс — это память, ну очень примитивно.

Я же не говорил «всех проблем». Для оставшихся проблем есть интерфейс IDisposable. Конечно, работать с ним не так удобно, как с деструкторам в C++.

Почти все эти "проблемы" решаются изучением справки к компилятору и включением флагов.


-Werror

-Wall
-Wextra
-Wpedantic

-Wcast-align
-Wcast-qual
-Wconversion
-Wctor-dtor-privacy
-Wenum-compare
-Wfloat-equal
-Wnon-virtual-dtor
-Wold-style-cast
-Woverloaded-virtual
-Wredundant-decls
-Wsign-conversion
-Wsign-promo
Спасибо! Я с этим аспектом проблемы глубоко не разбирался, хотя призывал программировать без предупреждений почти в каждом раздела. Но замечу, что это флаги GCC, в других компиляторах по другому. И с таким количеством флагов работать не очень удобно. Считаю, что лучше, если программист распознает эти проблемы «в лицо», то есть видит в коде, а еще лучше, если сразу пишет правильный, более безопасный код.

Это флаги ГЦЦ и Кланга.


С таким количеством флагов работать необходимо. А "распознавать в лицо", то есть, в переводе на русский, работать компилятором крайне вредно.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории