Знакомимся с полезными инструментами STL — std::remove() и std::remove_if()

Добрый день, всем привет!

Снова в эфире рубрика «Вы не спрашивали, но мы отвечаем», раздел «Программирование», глава «Что нового я узнал в сейчас лет».

Например, не так давно я узнал, что <a href="https://en.cppreference.com/w/cpp/container/unordered_map">std::unordered_map</a> не сортирует данные в отличие от <a href="https://en.cppreference.com/w/cpp/container/map">std::map</a>. А много-много лет назад (в 2007-м году) нам пришлось реализовывать бинарный поиск, чтобы ускорить вставку элементов в std::map (там жил кэш текстур) вместо того, чтобы взять std::unordered_map. Наш просчёт немного оправдывает то, что мы были молоды, неопытны и std::unordered_map появился спустя пять с лишним лет после описываемых событий.

Вообще, я не отношусь к тем людям, которые ежедневно читают свежайший стандарт C++, подчеркивая карандашиком важные места. Скорее, я начинаю читать стандарт, когда нужно найти решение текущей задачи. Так, например, я совершенно случайно наткнулся на <a href="https://en.cppreference.com/w/cpp/memory/enable_shared_from_this">std::enable_shared_from_this</a>, когда просматривал код нашего проекта, поминая тимлида нехорошими словами . Там был метод типа make() у класса, который должен вернуть <a href="https://en.cppreference.com/w/cpp/memory/shared_ptr">std::shared_ptr</a> от экземпляра этого класса. Если вы наследуете класс от std::enable_shared_from_this, то у вас появляется метод <a href="https://en.cppreference.com/w/cpp/memory/enable_shared_from_this/shared_from_this">shared_from_this()</a>, и дело в шляпе. Поскольку это было пять лет назад, уже не помню всех подробностей, но сначала было не очень, а потом резко стало хорошо! )

Каких-то одиннадцать лет назад я написал статью про эффективное удаление элементов массива. Тогда единственный способ, который я знал, выглядел следующим образом:

auto iter=data.begin()
while(iter != data.end()) {
    if (condition(*iter)) {
        iter = puf(data, iter);
    else {
        ++iter;
    }
}

Вся упомянутая в статье магия с перемещением в конец массива и удалением происходит в puf(). ЗдОрово, правда?

Оказывается, есть метод лучше, и имя ему — <a href="https://en.cppreference.com/w/cpp/algorithm/remove">std::remove_if()</a>, а самый интересный момент, что этот метод не удаляет элементы, а перемещает их в конец массива, возвращая итератор на начало этого кладбища погибших элементов. Между прочим, эксперимент показал, что после итератора лежит мусор.

С новыми знаниями, удаление элементов из контейнера будет выглядеть так:

auto iter = std::remove_if(data.begin(), data.end(), condition);
data.erase(iter, iter.end());

Что является более продвинутым вариантом и пишется короче, с чем я вас и поздравляю!

Фунция std::remove_if() удаляет элементы, для которых условие истинно, а std::remove() удаляет элементы с конкретным значением.

Про Турцию в целом и отдых в Алании в частности

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

Турция. Панорама Алании

Жалобы

Для ЛЛ: обратный вылет задержали на 12 часов без каких либо компенсаций.

1. Турецкие авиалинии Turkish Airlines

Задержали рейс домой на двенадцать, сука, часов, без предоставления отеля. В качестве компенсации каждого пассажира задержанного рейса посадили в самолёте у окошка, а если серьезно, то всем, по большому счету, плевать на проблемы отдыхающих: авиакомпании, туроператору, турагентству и отелю.

2. Туроператор Пегас Туристик

Во время трансфера на вылет, развернули автобус и вернули всех туристов обратно без объяснения причин, при этом водитель ни русского, ни английского не знает. На кой чёрт нанимают водителей для трансфера иностранных туристов без знания языков для меня загадка. Цитирую водителя: «проблемо, но инглиш» и чемодан на улицу херак. Общались с помощью непереводимой игры слов и администратора отеля, о котором будет ниже. Плюс к этому хочу отметить отельного гида, в обязанности которой входит лишь впаривание экскурсии по цене примерно вдвое обычных. Экскурсии категорически рекомендую покупать на улице: в итоге вас заберёт автобус и привезёт к тем, кто купил её дороже у отельного гида.

3. Турагентство АнексТур

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

4. Отель Сариташ

Захотели доплаты (30$) при вселении, чтобы был вид на море. Убрались в номере (плохо) ровно один раз за две недели после третьей жалобы на ресепшн. Постельное бельё поменяли только на десятый день. Каждый завтрак/обед/ужин организовали очередь за горячей едой (кости куриные или жареная рыба, яичница и блинчики на завтрак). Столовка почему-то вызывала стойкую ассоциацию с фильмом Платформа. К счастью, мы были на первом уровне. Но надо отдать должное: блинчики были вкусные и администратор не оставил нас без горячей пищи во время ожидания трансфера: номер для поспать не дали — авиакомпания/туроператор пожалели компенсировать €45, но поесть обед, ужин и напитки — пожалуйста.

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

Экскурсии

Среди отдыхающих нам встречались русские, украинцы, молдаване, поляки, немцы, англичане. Плюс к этому общались с узбеком, норвежцами и иракцем из Дании. Конфликтов на тему Украины ни с кем не возникало. А у норвежцев, как и положено северному народу, был с собой лёд!

Экскурсии брали у эксцентричного Альберта 5★ и Тимура — турка из Оренбурга. Альберт 5★ говорит на английском, его коллега Максим на русском. Тимур знает русский в совершенстве. Будете заказывать экскурсию с оплатой по частям: требуйте, чтобы оставшуюся сумму писали в турецких лирах, иначе придется заплатить на месте больше, чем рассчитывали. Про каждую экскурсию напишу отдельно.

1. Хамам (Альберт 5★, $20 за двоих)

Многие рекомендуют посетить хамам сразу после прибытия, чтоб загар лучше ложился брат. В назначенное время нас посадили на измену к двум джигитам, которые знают только турецкий, в старый рыдван и увезли в неизвестном направлении вдоль моря в сторону Сирии. Километров через 10-15 мы приехали в подвал/автостоянку за шлагбаумом возле какого-то отеля, где собственно находился хамам. Было несколько тревожно. Нам предоставили шкафчики для личных вещей. После переодевания полежали в парилке, потом в парной, затем нас хорошенько потерли скрабом и после сделали мыльный массаж, затем чай с крендельками, маска глиняная на лицо и, когда мы вконец разомлели: массаж с маслом. В итоге, те же джигиты на том же рыдване отвезли нас обратно. Мне всё понравилось, супруге тоже. Узнал, что левая рука у меня гнётся хуже правой — пойду у ревматолога спрошу, как с этим быть. Хамам рекомендую к посещению.

2. Катамаран (Альберт 5★, $40 за двоих)

Включает в себя путешествие на лодке и купание. Проблема в том, что с маршрутами для лодок в той части Турции наряженка, поэтому в 10:30 из порта стартует флотилия из 12-ти одинаковых посудин и идут они все по одному и тому же маршруту, в котором всего семь потенциальных мест для купания. Нам не повезло и купаться мы останавливались всего два раза по 15 минут и один из них в грязной воде. Питание включено, кола, фанта, спрайт безлимит, алкоголь за деньги.

3. Джиппинг (гид туроператора, $70 за двоих)

Катания на открытых джипах (Land Rover Defender) по местным просёлочным дорогам с заездом в местную деревню за покупками, потом везут покушать и искупаться в бассейне. Ушлый турок хотел нас нагреть во время обеда: вместо 250 турецких лир насчитал €11 или 295 лир за напитки, но супруга убедила его в обратном. Причём тут евры никто не понял, уговор был про лиры. Будьте внимательны. Катания на джипах сопровождаются обливанием водой других джипов и пассажиров в них из бутылок — получается очень весело. Рекомендую отдельно джипы не брать, а выбрать экскурсию в Сападере каньон — получается тоже самое. В конце вам предлагают купить набор фотографий и видео о поездке за $25.

4. Судно Relax (Тимур, $50 за двоих)

С одной стороны тоже самое, что Катамаран, а с другой народу поменьше и купаться разрешают по 40 минут вместо 15-ти. Плюс музыки поменьше и народа. Остановок было, вроде, четыре. Я настолько расслабился, что в первый раз обгорел. На судне даже есть своя маленькая толстая собачка.

Судовая собачка

Никакой суеты, релакс как он есть и прыжки в воду с третьего этажа (я лично только со второго прыгал, выше уже сцу). Рекомендую.

5. Каньон Сападере (Тимур, 1000₺ за двоих)

Почти тоже самое, что джиппинг, но машин одновременно семь-восемь вместо трёх и поливать водой становится веселее и чаще. Там мы познакомились с харизматичным дедом из Швейцарии, который умеет танцевать руками, держась одной ногой за джип. Как зовут — не знаю. Наверно Клаус, мне кажется всех дедов в Швейцарии зовут Клаус и говорят они на швейцарском языке, который очень уж похож на немецкий.
Швейцарский дед, возможно, Клаус.
В конце экскурсии так же предлагают фотографии и видео за $20, но нам сделали хорошую скидку, как друзьям Тимура.

6. Квадроциклы (Тимур, $35 за один байк плюс пассажир)

Квадроциклы запомнились тем, что не вся экипировка включена в стоимость: только шлем и шапочка под него. Не хочешь пыль глотать — плати за бандану, не хочешь камнем в глазик — плати за очки. Заранее об этом Тимур упомянуть забыл. А так два заезда с перерывом в 15 минут по пыльным дорогам в лесу возле бетонного завода. Грязное потом всё: ухи, глаза, нос, шея, колени, но всё равно довольно интересно. Если любите такую технику, как я, то рекомендую. Помните про экстра расходы: не забывайте в отеле солнцезащитные очки — они вам точно пригодятся и купите заранее бандану, в других местах она дешевле в два-три раза.

Итого

Турки много и часто курят. Я хоть и бросил в 21-м году (стаж 25 лет), но от табачного дыма до сих пор кайфую. Ещё в Турции любят котиков и чёрный чай.

Котёнок спит на скамейке, парк Ататюрка, Алания, Турция

Деньги брали с собой в наличных долларах, которые были накоплены ещё в довоенное время. Дополнительно переводили себе деньги через приложение от компании CONTACT по грабительскому курсу. Инфляция в Турции бешеная: фуникулёр был 160₺, через день — 190₺, а в 2018 стоил всего 90₺. За один доллар сначала давали 22.83₺, через две недели уже 24₺. Так что нашему рублю ещё есть куда стремиться. Здорово, правда?

Личинки шелкопряда, 1940 год, Алания, Турция

Несмотря на всё выше перечисленное, отпуск в целом понравился. Единственное тёмное пятно: это задержка рейса на 12 часов и в корне неправильные действия всех к этому причастных, в остальном мы отдохнули, наелись и накупались.

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

И раз уж вы дочитали до этого места: самый вкусный суп Том Ям делают в ресторане Mai Thai в Мурино, не благодарите. Заказывайте на кокосовом молоке — не ошибётесь.

Пару слов про компьютерный звук

Компьютерный звук в компьютере представлен в виде (сюрприз-сюрприз!) массива чисел. Минимальная единица звука в компьютере — это семпл — одно число. Частота дискретизации — это количество семплов в одной секунде. Всем известная цифра 44100 — это всего лишь сорок четыре тысячи сто семплов в секунду. Семпл может быть в разных форматах и их достаточно много, чтобы описывать в этой статье. Лично я встречался с форматом float32 и с одним байтом (std::uint8_t) на семпл.

Расскажу в общих словах алгоритм проигрывание звука на компьютере. Я так делал, друзья делали всем понравилось и, в целом, везде одинаковый принцип. Алгоритм такой:

  1. Создать два буфера (A и B) в нужном формате
  2. Заполнить буфер A семплами
  3. Отдать буфер A на проигрывание звуковой карте
  4. Заполнить буфер B семплами
  5. Отдать буфер B на проигрывание звуковой карте
  6. Перейти к шагу 2.

Когда звуковая карта заканчивает проигрывать буфер, она запрашивает новый, который должен быть готов к этому моменту. Таким образом, как только вы отдали один буфер на проигрывание, немедленно надо заполнять следующий. Всё это, разумеется, делается в отдельном потоке с максимальным приоритетом, потому что пользователь зараза сразу слышит помехи своими ушами. Понизить FPS и немного схалтурить тут не получится.

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

«А как же второй канал, стерео и звук вокруг?», — спросит внимательный читатель. Лично я сталкивался только со стерео звуком, поэтому про пяти и более канальный звук не расскажу. Семплы для стерео звука располагаются в буфере interleaved, по очереди: LRLRLRLR. А значит для стерео звука количество семплов на секунду в буфере удваивается. И на одну секунду для частоты 44100 надо уже 88200 семплов.

Настройка title для каждой страницы сайта на WordPress без плагинов

Просто добавьте этот код в functions.php вашей темы:

function your_document_title($title) {
  $sep = ' | ';
  $array = [];
  $term = get_queried_object();

  global $page;

  if (is_singular()) {
    if ($page) {
      array_push($array, 'Часть '.intval($page));
    }
    array_push($array, get_the_title($term));
  }
  else if (is_paged()) {
    array_push($array, 'Страница ' . intval(get_query_var('paged')));
  }

 if (is_search()) {
    array_push($array, 'Результат поиска по запросу "'.esc_html($_GET['s'].'"'));
  }
  else if (is_category($term)) {
    array_push($array, 'Категория "' . $term->name . '"');
  }
  else if (is_tag($term)) {
    array_push($array, 'Метка "' . $term->name . '"');
  }

  array_push($array, get_bloginfo('name'));

  if (is_front_page() && !is_paged()) {
    array_push($array, get_bloginfo('description'));
  }

  return implode($sep, $array);
}
add_filter('document_title', 'your_document_title');

Эти строчки добавляют фильтр к методу document_title.
Для каждого заголовка страницы WordPress вызывает наш код следующим образом:

$title = your_document_title(default_title());

Правила такие:

  • для одиночных постов — «Название поста»
  • для страницы категории выводится — Категория «Название»
  • для страницы тега выводится — Метка «Название»
  • для главной страницы «Название сайта | Описание сайта»
  • для постов разбитых на части добавляется «Часть N» в начале
  • для страница поиска типа /s=QUERY «Результат поиска QUERY»
  • для страниц пагинации типа /page/N добавляется «Страница N» в начале
  • для всех страниц добавляется информация из поля Настройки->Общие->Название сайта
  • для всех страниц, кроме главной и страниц пагинаций, в конце добавляется информация из поля «Настройки->Общие->Краткое описание»

Добавляем мета тег canonical к каждой странице сайта на WordPress без плагинов

Всем привет! Чтобы добавить запись типа meta rel="canonical" href="url" к каждой странице вашего сайта на WordPress, добавьте этот код в functions.php вашей темы:

function remove_args($url) {
  $parsed = parse_url($url);

  $fragment = '';

  if (array_key_exists('fragment', $parsed)) {
    $fragment = '#' . $parsed['fragment'];
  }

  return sprintf("%s://%s%s%s",
    $parsed['scheme'],
    $parsed['host'],
    $parsed['path'] ?? '',
    $fragment);
}


function print_canonical_link() {
  $url = "";

  // Одиночная страница
  if (is_single()) {
    global $page;
    // Пост из нескольких частей
    if ($page) {
      $url = get_pagenum_link($page);
    }
    else {
      $url = get_permalink();
    }
  }
  // Страница пагинации типа что-то-там/page/N
  else if (is_paged()) {
    $url = get_pagenum_link(get_query_var('paged'));
  }
  // Главная страница сайта
  else if(is_front_page()) {
    $url = get_home_url();
  }
  // Страницы категории или тега
  else if(is_category() || is_tag()) {
    $url = get_term_link(get_queried_object());
  }

  if ($url) {
    echo '<link rel="canonical" href="'.remove_args($url).'" />';
  }
}
add_action('wp_head', 'print_canonical_link');

Подробности для непосвящённых: функция print_canonical_link() выводит запись вида
<meta rel="canonical" href="url" /> во время вызова штатной функции wp_head(), что очень уважают поисковые системы, но это неточно. А функция remove_args() удаляет GET аргументы вида «?key=value» из URL. Критика, замечания, пожелания приветствуются.

Личный блог Евгения Жирнова