Pull to refresh

Comments 32

А как с советом № 20 перекликается вот такое из совета № 19?

if (int status = Go_2(buf_1, buf_2); status != STATUS_OK)

Конкретно для этого кода вполне приемлемо, так как код прост и однотипен. И вообще синтетика. В целом, любой совет, не отменяет необходимость думать в процессе создания хорошего кода :)

самый богатый список антипаттернов программирования я подчеркнул в Misra C++

Размер указателя и int — это всегда 4 байта

Сколько проблем доставил этот подход (кстати, весьма популярный одно время) при переводе 32 бит проектов на 64 бит.

Угу, прежде, чем так экономить на спичках, надо помнить, что такой подход может похоронить продукт, как это было с flash (сначала долго не могли выпустить 64-битную версию плагина, а затем так долго фиксили баги, что apple отказалась поддерживать flash в iOS) и нативным форматом сохранения файлов ms office (который был по сути слепком памяти, и пришлось сначала выкатывать не привязанный к архитектуре ooxml, и только потом выпускать 64-битный офис).

По вредному совету №20
скажите, как человеку который не программировал уже лет 15,
сейчас принято писать в таком стиле:
f() {
}
а не
f()
{
}
Если да, то почему?

У нас вот принято писать открытие скобки на новой строке. На деле это вообще не важно, привыкаешь к любому варианту минут за 10. У варианта

f() {
}

Есть несколько плюсов:

  1. Меньше строк кода делающих ничего. Не всегда это хорошо, частенько прям не хватает именно пустоты.

  2. Консистентно с другими скобками, потому что обычно при сложных условиях мы пишем:

if ( 
  cond1 
   && cond2
   && cond3
) {
}

Сейчас принято со стилем вообще не заморачиваться. IDE форматирует код на этапе написания согласно конфигу clang-format, а во время CI код будет проверен на соответствие стилю.

Сейчас принято получать готовый код от ChatGPT и не заморачиваться по остальным моментам тоже.

PS: Многие по-старинке пишут код в vi. Во всяком случае у меня в компании именно так.

Есть с clang-format несколько серьезных проблем.

Его нельзя настроить так, чтобы код не выглядел убогой лапшой без всякой семантики. Из самого забавного, в нём невозможно настроить вот такое форматирование:

static inline ::some::deep::namespace::ClassName::Ptr
someQuiteLongFunctionName (
    int param1,
    int param2,
    int param3
) {
}

Максимум, что может породить clang-format:

static inline ::some::deep::namespace::ClassName::Ptr
someQuiteLongFunctionName ( int param1,
    int param2,
    int param3) 
{
}

Или даже что-то банальное, вроде вот такогого выравнивания в условиях:

if(
    condition1
    || condition2
    || condition3
) {
}

И еще огромную кучу вещей. Например, у нас есть кодовая база, где было принято все лямбды оформлять следующим образом:

auto some_lambda = 
    [a, b, c, d, movable = std::move(val)]
    (int x, void* ptr) -> bool
    {
        //Body content
        return true;
    };

И такой код пускай и слегка громоздкий, зато оч легко читать, т.к. список захвата, параметры, возвращаемое значение и тело лямбды разделены логически.

Опять же, много где в алгоритмах передаются лямбды и когда они небольшие - проблем нет, можно хоть в одну строку всё писать. А вот когда условия становятся сложнее, то неплохо бы иметь форматирование вроде такого:


std::transform(                    //Семантически разделяем
    std::begin(in), std::end(in),  //Вход
    std::back_inserted(out),       //Выход
    [](auto&& v) {
         //Какое-то сложное преобразование
    }
)

И хоть об стену убейся невозможно настроить clang-format соответствующим образом, а проект уже есть и код есть.

И тут или плодить мегакоммитище, который из стройного кода которому все привыкли породит тонну мерзкой лапши, или написать свой тул по форматированию, или забить понадеяться, что люди в целом не дураки и способны плюс/минус соблюдать соглашения принятые в коде.

Люди в целом не дураки, но не способны соблюдать соглашения по форматированию, даже если очень-очень хотят. А в большинстве своём они не хотят - им всё равно. Гораздо интересней думать о программировании, а не думать о том где и как расставлять скобки.

Мой опыт говорит, любой, даже самый паршивый автоформат гораздо лучше джентельменских соглашений.

Мой опыт мне говорит, что процесс перехода на автоформат бывает оч болезненным. Паршивый автоформат создаёт код, который неприятно читать) Что как раз-таки мешает думать о программировании.

Но в целом, ничего ужасного в автоформате я не вижу. Clang-format позволяет сделать плюс/минус вменяемое форматирование к которому можно привыкнуть. Я лишь хотел сказать, что существуют некоторые факторы, которые препятствуют его повсеместному внедрению. Просто с телефона нормально оформить мысль не сумел.

Мне кажется, что вменяемое форматирование для всех разное. Например, принятые у вас стандарты мне откровенно не нравятся, но я смирился бы и с такими. Уверен, что через пару недель подобное форматирование перестало бы резать глаз и отвлекать от задачи.

У нас был опыт внедрения автоформата и ничего, прошло не так страшно. Сейчас я очень рад, что это удалось сделать. На крайний случай всегда можно конкретный кусок кода обрамить в С++ комментарии, подавляющие автоформат, хотя на практике это редко нужно

Скажем, то что предлагает clang-format без тонкой настройки режет мне глаза ну очень максимально. И я, к слову, так и не смог привыкнуть к этому.

Я не устраиваю войн по этому поводу и просто смиряюсь с этим, но глаза многое режет многие месяцы спустя)) Я просто привык, но это прям ужс-ужс)

Натроить под себя точно стоит. У нас нашёлся человек, который всё как нужно сделал

Есть ли вариант книги в PDF ? Или может быть даже в бумаге ?

PDF могу сделать, но не очень вижу смысл. Если хотите, сделаю и где-то выложу. Бумажная книга готовится. Текст достаточно сильно переработан, так как нельзя делать постоянные отсылки на внешние ресурсы. Что-то пришлось удалить, что-то расписать подробнее, что-то вынесено в раздел "терминология". Но в целом смысл будет тот-же.

Не смотря на то, что у меня есть некоторые расхождения во вмении с автором по ряду "советов", с удовольствием приобрету печатную версию. Хочу использовать как пособие для юных подаванов. PDF тоже не плохо было бы получить. Спасибо.

Откройте ссылку из статьи, Ctrl+P и напечатайте в PDF. Вроде выглядит достаточно неплохо.

Это я попробовал сразу - картинки и текст попадают на границы страниц в порезанном виде. Браузер Firefox.

По поводу проверки кода ошибки malloc.

Если пишете на C++ то он не должен использоваться, так как выделение /удаление памяти идут через new/delete.

И уже исписана куча книг от гуру что возврат кода ошибки был ошибкой, так как программа не может ничего сделать если нет памяти.

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

Поскольку нет гарантии что код который должен отработать не потребует выделения памяти подтопкой нибудь буфер

программа не может ничего сделать если нет памяти

Программа может сделать очень многое.

Во-первых, она может корректно завершиться, не выделяя новой памяти на куче.

Во-вторых, она может порытаться обойтись выделением меньшего объема памяти, ибо свободная память не обязательно полностью закончилась.

В-третьих, она может подождать, пока память освободится.

Закончившаяся куча - это все-таки не закончившийся стек (хотя в том же встраиваемом ПО можно и в этом случае сделать очень много, не дерргая стек вообще или сбросив его).

в начале 2000х сталкивался с таким подходом: программе в случае нехватки памяти надо было в любом случае выполнять некий пост-код. Для этого отъедали глобально небольшой кусок памяти при старте, и в случае нехватки перед выходом освобождали глобал - выполняли нужный пост-код на освободившейся памяти.

и да, не работало :)

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

Кстати, подход с резервированием блока должен гарантировать, что пост-коду хватит места после освобождения блока. И не стоит путать нехватку памяти с повреждением кучи.

Поэтому Строустроп и Ко в C++ заставили оператор new выкидывать исключение а не возвращать код ошибки. «А мужики то и не знают…»

Корректно завершить значит вызвать все деструкторы, которые должны освободить ресурсы. При нехватке памяти никаких гарантий нет. Идея зарезервировать память а в случае исключения словоблудить -так себе костыль. Если лишнюю не резервировать то может быть и нехватки памяти бы не было.

Плюс вы не можете контролировать выделение памяти в ОС. Поскольку куча процессов свои буфеты резервирует

Корректно завершить - обеспечить, чтобы ничего не сломалось (не разрушилась структура важных файлов только потому, что что-то не успели записать, не сгорела железка, которую нужно периодически выключать, чтобы не перегрелась, скинуть важное из памяти на диск, чтобы не пропало). А если что-то там не освободилось из незначительного, или деструктор третьестепенного класса не вызвался, так и пес с ним.

Впрочем, иногда завершение может быть абсолютно корректным (с закрытием всего открытого и вызовом всех деструкторов, если там память не выделяется). Оно, естественно, не всегда возможно, но иногда не только возможно, но и необходимо.

Ну а в целом в статье это и написано: проверять не нужно, кроме тех случаев, когда нужно.

Существуют системы с различными моделями данных, где int может содержать и 8 байт, и 2 байта и даже 1 байт!

Тут очень важно сделать уточнение — речь идёт не о том байте, о котором большинство сразу могло подумать (и который правильнее называть “октет”), а о том, который определён стандартами языков С или С++ как нечто адресуемое и способное хранить любой символ из набора символов среды исполнения ("addressable unit of data storage large enough to hold any member of the basic character set of the execution environment")

С системами, на которых sizeof(char) == sizeof(short) == sizeof(int) == sizeof(long) == 1, мне довелось работать 35 лет назад :)

std::unique_ptr<T[]> ptr(new T[count]);

Можно ещё «правильнее» заморочиться
auto ptr = std::make_unique_for_overwrite<T[]>(count);
Sign up to leave a comment.