вторник, 4 июля 2023 г.

[prog.c++] Несколько интересных статей с devblogs.microsoft.com (про std::tuple и std::index_sequence)

Сохраню в склерозник ссылки на несколько статей, которые заставили меня поломать мозги, т.к. тема std::index_sequence в C++11 одна из самых мной нелюбимых. Редко пользуюсь этими самыми std::index_sequence и не совсем понимаю как эта заумная хрень работает, помогает разве что заучивание.

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

Mundane std::tuple tricks: Selecting via an index sequence

Mundane std::tuple tricks: Selecting via an index sequence, part 2

Mundane std::tuple tricks: Creating interesting index sequences

Mundane std::tuple tricks: Finding a type in a tuple

Там еще есть статьи на тему std::tuple, я здесь сохранил только те, которые зацепили лично меня.

суббота, 1 июля 2023 г.

[life.cinema] Очередной кинообзор

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

Фильмы

Тайлер Рейк: Операция по спасению 2 (Extraction 2, 2023). Отличный боевик для просмотра с отключенными мозгами. Кому понравилась первая часть, может смело посмотреть и вторую. Хотя продолжение мне показалось еще более сказочным, чем начало.

Незавершенное дело (La maniobra de la tortuga, 2022). Неплохая социальная чернуха из Испании. Неплохая, но не более того.

Ограбление по-бразильски (São Paulo Heist, 2018). Интересная история, и следить за ней было любопытно. Но в целом не цепляет, видно, что это и не голливудское, и не европейское кино. Как будто авторам мастерства в воплощении своих замыслов и не хватило.

Приглашение к убийству (Invitation to a Murder, 2022). Снято красиво. Но это, пожалуй, единственное достоинство фильма. Персонажи картонные и общее впечатление какой-то отталкивающей приторности. Детективная составляющая тоже так себе.

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

Беглец (Kandahar, 2023). Очень и очень посредственно.

Гипнотик (Hypnotic, 2023). Во-первых, это не "боевик, триллер, детектив", как сказано в описании, а чистой воды фантастика. Если к нему относиться именно так, то ожидания более полно совпадут с реальностью. Во-вторых, это очень и очень средненькая фантастика. Что-то вроде "Начало" от Нолана, но на совсем уж минималках. В-третьих, ощущается и бюджетность, и отсутствие нормальной актерской игры у ряда персонажей (включая главного героя). Так что общие впечатления очень посредственные.

Тихий садовник (Master Gardener, 2022). Вот не понял что это было. Либо это реально хороший, хоть и своеобразный, фильм. Либо это какое-то халтурное покаяние перед BLM в стиле "главный герой же смог стать хорошим, хоть и был фашистом в прошлом". Мне кажется, что все-таки второе. Поэтому рекомендовать к просмотру не буду.

Форсаж 10 (Fast X, 2023). Они смогли сделать хуже, чем было в 9-ом! Редкостная муть и дрянь, смело можно не смотреть.

За нас с вами (2023). Посмотрел и как будто подборку "Огонька" за 1988-й год пролистал. Мне не зашло. Ни с точки зрения рассказанного, ни с точки зрения качества исполнения.

Сериалы

Мейр из Исттауна (Mare of Easttown, первый сезон, 2021). Снято добротно, смотреть интересно, после завершения сожалений о напрасно потерянном времени нет. Но вот развязка выглядит слишком уж надуманной.

Связь (Liaison, первый сезон, 2022). Не смотря на наличие известных актеров и неплохое начало по итогу оказалось редкостной херней.

Мерзлая земля (первый сезон, 2023). Случайно ввязались в просмотр, потом было жалко бросать, т.к. хотелось узнать развязку. Но лучше было бы бросить сразу, т.к. редкая ерунда, на которую не стоит тратить свое время.

четверг, 22 июня 2023 г.

[prog.c++] Отличная статья для тех, кто хочет прокачать свое знание C++ных шаблонов

Вот: C++ template: Trying to Make the Easy Way. Букв много, но оно того стоит. Да к тому же там еще и ссылки на дополнительные материалы.

Совсем новичкам в C++ я бы ее рекомендовать не стал. Но если общие представления о шаблонах есть и хочется пойти дальше, то будет полезно. Да и бывалым C++никам имеет смысл ознакомиться. Я, например, для себя как минимум две вещи отметил:

Во-первых, вот такая форма SFINAE:

template <typename Object>
auto makeString(const Object& object) -> decltype(object.to_string())
{
    return object.to_string();
}

Я же, признаюсь, больше по старинке, через std::enable_if.

Во-вторых, необходимость применения std::forward в случаях, когда нужно вызвать какой-то метод у объекта, переданного посредством universal reference:

template <HasToString Object> // Это C++20, да. Не всем еще доступен.
std::string makeString(Object&& object)
{
    return std::forward<Object>(object).to_string();
}

В общем, мне понравилось. К прочтению рекомендую.

понедельник, 19 июня 2023 г.

[prog.c++] Давненько не приходилось видеть в C++ных проектах исключений, не производных от std::exception...

Сам я уже давно взял за правило, что если в проекте используются исключения, то собственные классы исключений в проекте должны быть прямо или косвенно унаследованы от std::exception. Прямо унаследованы -- это напрямую от std::exception. Косвенно -- это когда есть какой-то промежуточный класс-родитель, вроде std::runtime_error или some_3rd_party_lib::exception (при этом промежуточный класс-родитель все равно восходит к std::exception (прямо или косвенно)).

Следование этому правилу сильно упрощает жизнь. Т.к. можно просто писать:

try {
  ... // Какие-то действия.
}
catch( const std::exception & x ) {
  ... // Здесь мы точно знаем, что все исключения перехвачены.
}

Тогда как если у нас где-то есть выброс класса, не производного от std::exception (а то и вообще какого-нибудь int-а или std::string), то жизнь становится веселее и непредсказуемее.

Выделить можно два момента:

Во-первых, мы можем вообще не предполагать, что исключение какого-то левого типа XYZ у нас может вылететь. Хотя бы потому, что мы имеем дело со сторонней библиотекой X, в которой используется библиотека Y, в которой используется библиотека Z. И начиная с какой-то версии Z появился тип XYZ. Исключения этого типа не перехватили (возможно по недосмотру) в Y, и не перехватывали (понадеясь на Y) в X. Соответственно, мы снаружи X про XYZ вообще не сном, ни духом. И если в нашем коде обработка исключений сделана только через catch(const std::exception &), то у нас появляются серьезные проблемы, т.к. XYZ будет пролетать "насквозь" и, скорее всего, будет убивать наше приложение (или приложение того, кто использует наш код).

Во-вторых, даже если мы перестраховались и сделали в дополнение к catch(const std::exception &) еще и catch(...), то в этом перестраховочном catch мы мало что можем сделать. Даже толком не сможем залогировать тип пойманного исключения и полезную информацию из него.

В общем, сам давно придерживаюсь принципа, что все собственные исключения должны наследоваться от std::exception, и давным-давно не видел нарушений этого принципа в сторонних C++ных библиотеках, с которыми доводилось сталкиваться. Последний раз что-то подобное, ЕМНИП, видел в OTL лет 15 назад. Но там удалось убедить автора сделать специальные настроечные макросы OTL_EXCEPTION_DERIVED_FROM и OTL_EXCEPTION_IS_DERIVED_FROM_STD_EXCEPTION, чтобы otl_exception был наследником std::exception.

Но вот сегодня в дикой природе увидел исключения, не производные от std::exception. Например:

class EndOfStunMsgException {
public:
  EndOfStunMsgException() {}
  virtual ~EndOfStunMsgException() {}
};

Причем в копирайте там указаны даты 2011, 2012 и 2013 годы. Т.е. сильно после того, как появился стандарт C++98 (до этого формально std::exception в языке не было, так что каждый городил свою иерархию исключений по собственному разумению).

В связи с этим возникает вопрос: ну вот как так-то?

Нужно сказать, что там вообще к C++ному коду есть вопросы. Например, std::string используется, но специфическим образом:

  void addSTMessageIntegrity(std::string &uname, std::string &upwd) {

    if (!_constructed || !isCommand())
      throw WrongStunBufferFormatException();

    uint8_t *suname = (uint8_t *)strdup(uname.c_str());
    uint8_t *supwd = (uint8_t *)strdup(upwd.c_str());

    stun_attr_add_integrity_by_user_short_term_str(_buffer, &_sz, suname, supwd, SHATYPE_SHA1);

    free(suname);
    free(supwd);
  }

Метод принимает строки по неконстантной(!!!) ссылке, но содержимое параметров uname и upwd не меняется. Более-то, зачем-то делается копия их содержимого для вызова stun_attr_add_integrity_by_user_short_term_str. Временная копия, которая затем сразу же удаляется. Но если взглянуть внутрь stun_attr_add_integrity_by_user_short_term_str, то можно увидеть вот это:

int stun_attr_add_integrity_by_user_short_term_str(
    uint8_t *buf, size_t *len, const uint8_t *uname, password_t pwd, SHATYPE shatype) {
  if (stun_attr_add_str(buf, len, STUN_ATTRIBUTE_USERNAME, uname, (int)strlen((const char *)uname)) < 0)
    return -1;

  hmackey_t key;
  return stun_attr_add_integrity_str(TURN_CREDENTIALS_SHORT_TERM, buf, len, key, pwd, shatype);
}

Т.е. указатель на uint8_t все равно воспринимается как указатель на char (т.е. здесь нет никакой защиты от гипотетических случаев, когда почему-то char имеет другое представление, нежели uint8_t). Да еще и длина строки вычисляется через strlen, хотя изначально у нас есть std::string, длина которого известна через std::string::size().

И, кстати говоря, код возврата stun_attr_add_integrity_by_user_short_term_str в плюсовой addSTMessageIntegrity тупо игнорируется и теряется. Как и потенциальные ошибки strdup.

В общем, я уже давно не доверяю утверждениям "обычно C++ работает медленнее, чем чистый Си", потому что в достатке насмотрелся на случаи подобной пессимизации C++ного кода.


Сожалею, если этот пост получился излишне злым, но пригорело. Я уже несколько лет как безуспешно предлагаю свои услуги в качестве опытного C++разработчика. Такое ощущение, что это нафиг никому не нужно, поголовно у всех "свои крутые C++ специалисты". А как доведется в код заглянуть, так там и функции-простыни по 200 строк, и тотальное отсутствие комментариев, и коды возврата read не проверяются... Ну или вот такое, как показано выше. Ну OK, крутые так крутые.


Проект, фрагменты из которого были приведены в посте, мне использовать не нужно. Просто потребовалось получить представление о STUN, TURN, ICE и пр. Вот в процессе сбора информации и заглянул ненароком.

среда, 14 июня 2023 г.

[prog.c++] Несколько интересных статей с devblogs.microsoft.com

В последние дни на глаза попалось несколько любопытных статей, ссылки на которые захотелось сохранить в склерознике. Вот, делаю это в виде блог-поста.

How to check if a pointer is in a range of memory. Просто и наглядно на тему того, почему сравнивать указатели на больше/меньше так себе идея (хотя, признаюсь, временами мало того, что хочется, так еще и нужно). Там же описан и один легальный способ сделать это (если у вас в компиляторе есть uintptr_t). Если не ошибаюсь, еще безопасно использовать std::less для указателей. Но если ошибаюсь, то буду признателен, если меня поправят. Спасибо ув.тов.Сергею Скороходову за ссылку.

Reordering C++ template type parameters for usability purposes, and type deduction from the future. Имхо, полезная статья для тех, кто начинает упарываться шаблонной магией и сталкивается с тем, что у того же std::vector есть несколько шаблонных параметров и иногда это приходится учитывать. Кроме того, в случае данной статьи следует обратить внимание и на комментарии.

The move constructor that you have to declare, even though you don’t want anyone to actually call it. Статья для тех, кто как и я не знал, что для NRVO (named return value optimization) требуется, чтобы в типе был описан конструктор перемещения. Даже не смотря на то, что вызов этого конструктора будет выброшен оптимизатором.

вторник, 13 июня 2023 г.

[network.ssh] Картинка-шпаргалка на тему ssh-tunneling

Не имел дела с ssh-тунелями лет пятнадцать, начал собирать информацию и понял, что штатные описания из man ssh до меня не доходят, туплю-с... А потом нашел отличную картинку-шпаргалку, которая все расставила по своим местам:

Источник: A Visual Guide to SSH Tunnels: Local and Remote Port Forwarding. Огромное спасибо автору картинки, Ivan Velichko (@iximiuz), за прекрасную по своей доходчивости иллюстрацию.

понедельник, 12 июня 2023 г.

[prog.c++] SObjectizer-5.7.5

Стала доступна версия 5.7.5 нашего проекта SObjectizer:

https://github.com/Stiffstream/sobjectizer/releases/tag/v.5.7.5

Ничего не было добавлено, ничего не было удалено. Исправлено поведение SObjectizer-а в некоторых ситуациях, которое могло приводить к проблемам. Подробнее можно прочитать в Wiki проекта: https://github.com/Stiffstream/sobjectizer/wiki/v.5.7.5

Эти и некоторые другие вещи (исправленные чуть ранее в 5.7.4.3) были обнаружены в процессе работы над новой версией 5.8.0. Разработка ветки 5.8 ведется с прошлого года и я боюсь предсказывать когда же состоится ее релиз. Но очень надеюсь на то, что основная часть работы с кодом уже позади. Далее предстоит обновить существующую и дописать недостающую документацию. Это, полагаю, минимум пару недель работы. Если, конечно, в процессе документирования не выяснятся какие-то косяки (что случалось в прошлом). Так что надеюсь, что 5.8.0 уже на финишной прямой, но вот длина этой самой прямой пока точно не известна :)

В общем, проект все еще жив и все еще развивается, так что не переключайтесь ;)