Комментарии 26
«if(strcmp(s,r)), когда правильно if(strcmp(s,r)==0)» — почему правильно?
Потому что это два противоположных условия. Код внутри
if(strcmp(s,r))
выполняется, когда они не равны, а if(strcmp(s,r)==0)
— когда равны.Правильно потому что это два противоположных условия? Серьезно? Откуда вы знаете что этот код должен делать?
Под «правильно» здесь понимается best practice. Довольно часто встречается код
Или
Этих ошибок бы не было, если писать явно == 0
if(strcmp(s,r)) {
// когда равны
}
Или
if(!strcmp(s,r)) {
// когда не равны
}
Этих ошибок бы не было, если писать явно == 0
Вы все еще продолжаете видеть какие-то ошибки в абсолютно корректном коде, мне это странно
В первом случае идет проверка на то, что первая строка больше второй. Во втором случае идет проверка на равенство строк.
Говорится о коварности неявного преобразования int в bool. Это может дать не тот результат, что хотелось бы получить.
Update: впрочем, ответ уже дали. Зависит, конечно, целиком и полностью от контекста применения. Но, наверное, удобнее читать будет, когда в явном виде будет указано возвращаемое значение. То есть, второй вариант.
Говорится о коварности неявного преобразования int в bool. Это может дать не тот результат, что хотелось бы получить.
Update: впрочем, ответ уже дали. Зависит, конечно, целиком и полностью от контекста применения. Но, наверное, удобнее читать будет, когда в явном виде будет указано возвращаемое значение. То есть, второй вариант.
Возможно автор хотел сказать что if (strcmp(s, r) == 0) наиболее часто использующийся случай для проверки равны ли строки. Я бы наверное оформил это таким образом
if (strcmp(s, r) ==0 ) — проверить равны ли строки
if (strcmp(s, r) !=0 ) — проверть не равны ли строки
А так да, говорить что 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 любимым языком, но вот с++ для меня является гораздо более удобным, так что это субъективно)
По поводу коллег сочувствую. А по поводу агитации да простите, её там совсем не чувствуется чего это я. (С# является моим 3 любимым языком, но вот с++ для меня является гораздо более удобным, так что это субъективно)
Ну корни у меня самые, что ни на есть плюсовые, с 90х. С++ я люблю и пишу на нем постоянно уже десятки лет. Моя цель — обратить внимание на проблемные моменты программирования на С++, которые легко могут привести к ошибкам. Программисты должны помнить об этих проблемах, не терять бдительности и при необходимости принимать необходимые меры. Никакой агитации за C# нет, просто хотелось показать, за счет чего, весьма близкий язык является более надежным и удобным. В целом стиль отзыва выглядит сумбурным, если не сказать истеричным. Практически ничего по существу ответить нельзя, так как никакой существенной критики нет, сплошные вопли.
НЛО прилетело и опубликовало эту надпись здесь
Не знаю, почему статью минусуют.
Вполне адекватно описаны пусть базовые, но все же нюансы языка. Указан к каждому пункту возможный путь борьбы с этими нюансами. Сравнение с C#, имхо, идет с точки зрения аналогии, а не рекомендации перейти на него. Не вижу причин для бомбежа.
Вполне адекватно описаны пусть базовые, но все же нюансы языка. Указан к каждому пункту возможный путь борьбы с этими нюансами. Сравнение с C#, имхо, идет с точки зрения аналогии, а не рекомендации перейти на него. Не вижу причин для бомбежа.
НЛО прилетело и опубликовало эту надпись здесь
Хочу еще раз обратить внимание, что никакой агитации за C# нет, просто хотелось показать, за счет чего, весьма близкий язык является более надежным и удобным. Сам я пишу на C++/C# где-то 50 на 50 уже много лет, и люблю оба языка. Считаю, что C++ программисту весьма полезно знать C# (ну на худой конец Java).
Статическая/динамическая типизация и строгая/нестрогая типизация это разные критерии классификации типизированных языков. Сильная типизация выделяется тем, что язык не позволяет смешивать в выражениях различные типы и не выполняет автоматические неявные преобразования. C++ спроектирован как язык со строгой типизацией, но с рядом послаблений в виде implicit conversions, из-за чего его чисто формально можно отнести к языкам с нестрогой типизацией. Вот статья на эту тему.
Программист может написать такие перегрузки, что потом будет пол дня думать, как они будут разрешатся в том или ином контексте. Я рекомендую так не делать. Потом перегруженные функции затрудняют анализ кода, особенно чужого, с помощью текстового поиска.
Этого в C# нет.
Не совсем понял, в чем суть возражения. Про классы, управляющие ресурсами у меня большая статья.
Я как раз и имел в виду производительность.
В C# при создании объекта сначала инициализируются все поля объекта (значениями, заданными при объявлении или по умолчанию), затем вызывается конструктор базового класса или перегруженный конструктор, если они указаны в списке инициализации, затем сам конструктор.
За все надо платить. Но в данном случае немного, такой вызов обычно происходит один раз.
Конечно, new/delete должны быть максимально инкапсулированы. Но полностью избавится от них не реально. C++ программист должен четко знать, как с ними правильно работать.
Помогает, но не всегда. Эти шаблоны не позволяют использовать пользовательские удалители, и в этом случае придется работать с сырыми указателями и надо знать, как правильно писать выражения без потенциальных утечек памяти.
Тут я выразился не совсем точно. Описываю ситуацию более подробно. Пусть в C# у нас есть базовый класс и производный. При создании экземпляра производного класса сначала инициализируются все поля базового класса и затем все поля производного. Только после этого вызывается конструктор базового класса и потом конструктор производного. Пусть в базовом классе определена виртуальная функция и она переопределяется в производном. Если в конструктор базового вставить вызов этой виртуальной функции, то вызовется переопределенная, соответственно, для объекта у которого уже инициализированы поля, но еще не вызывался конструктор. Довольно забавно. Если четко понимать, как это работает, то можно использовать.
Программист пишет unsafe-блоки на свой страх и риск. Почти все гарантии .NET отменяются.
Я же не говорил «всех проблем». Для оставшихся проблем есть интерфейс IDisposable. Конечно, работать с ним не так удобно, как с деструкторам в C++.
Нет. Это язык со статической типизацией, но она не строга ни в смысле гарантий, ни в смысле выразительности.
Статическая/динамическая типизация и строгая/нестрогая типизация это разные критерии классификации типизированных языков. Сильная типизация выделяется тем, что язык не позволяет смешивать в выражениях различные типы и не выполняет автоматические неявные преобразования. 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, в других компиляторах по другому. И с таким количеством флагов работать не очень удобно. Считаю, что лучше, если программист распознает эти проблемы «в лицо», то есть видит в коде, а еще лучше, если сразу пишет правильный, более безопасный код.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Проблемные аспекты программирования на С++