понедельник, 2 марта 2026 г.

[prog.c++] Применимость идиом copy-then-swap и move-then-swap при наличии кастомных аллокаторов

В продолжение недавно начатой темы. Есть очень удобная идиома copy-then-swap, которая позволяет легко и просто написать для своего типа оператор копирования, обеспечивающий строгую гарантию безопасности исключений.

Для примера рассмотрим некий вымышленный тип, который содержит внутри пару векторов:

class special_container {
  struct description { ... };
  struct payload { ... };

  std::vector<description> m_descriptions;
  std::vector<payload> m_payloads;
...
};

И мы хотим, чтобы у special_container был оператор копирования со строгой гарантией безопасности исключений. Для этого нам потребуются:

  • обычный конструктор копирования;
  • не бросающий исключений swap.

что достигается весьма просто:

class special_container {
  ...
public:
  // Swap сделаем через свободную функцию.
  friend void swap(special_container & a, special_container & b) noexcept
  {
    using std::swap;
    swap(a.m_descriptions, b.m_descriptions);
    swap(a.m_payloads, b.m_payloads);
  }

  // Конструктор копирования.
  special_container(const special_container & other)
    : m_descriptions{ other.m_descriptions }
    , m_payloads{ other.m_payloads }
  {}
...
};

Имея в своем распоряжении эти базовые инструменты можно сделать и оператор копирования:

special_container &
special_container::operator=(const special_container & other)
{
  special_container tmp{ other };
  swap(*this, tmp);
  return *this;
}

Фокус здесь в том, что возможные исключения вылетят при формировании объекта tmp. Но при этом ничего не меняется в this. А если при конструировании tmp исключений не случилось, то мы заменяем содержимое this содержимым tmp.

Еще один приятный фокус в том, что такая примитивная реализация прекрасно защищает и от присваивания самому себе. Впрочем, если экземпляры special_container "тяжелые", а вероятности самоприсваивания не нулевая, то можно и по старинке:

special_container &
special_container::operator=(const special_container & other)
{
  if(this != std::addressof(other))
  {
    special_container tmp{ other };
    swap(*this, tmp);
  }
  return *this;
}

Пока что все идет замечательно.

Но давайте представим себе, что нам потребовалось научить special_container работать с разными аллокаторами. Т.е. тип special_container превращается во что-то вроде:

template<typename Alloc>
class special_container
{
  struct description {};
  struct payload {};

  using alloc_traits = std::allocator_traits<Alloc>;
  using description_allocator = alloc_traits::template rebind_alloc<description>;
  using payload_allocator = alloc_traits::template rebind_alloc<payload>;

  std::vector<description, description_allocator> m_descriptions;
  std::vector<payload, payload_allocator> m_payloads;
...
};

Сможем ли мы и дальше пользоваться идиомой copy-then-swap?

И вот тут у меня есть сомнения. А в попытках разобраться как раз и получился этот пост.

У аллокатора может быть такое свойство как propagate_on_container_swap. Если это свойство выставлено в std::true_type, то при выполнении swap мы можем обменять аллокаторы для контейнеров.

Грубо говоря, допустим, что у нас есть собственный тип аллокатора:

воскресенье, 1 марта 2026 г.

[life.cimena] Очередной кинообзор (2026/02)

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

Фильмы

Человек с Земли (The Man from Earth, 2007). Фильм очень не новый, но посмотрел его только сейчас. Как по мне, так отличное кино, базирующееся на хорошем сюжете и тщательно выстроенных диалогах.

Убежище (Shelter, 2025). Обычный боевик со Стетхемом в главной роли, где круче него только горы и яйца. Но, в отличии от совсем уж сказочных "Пчеловода" и "Мастера", этот смотрится вполне нормально.

Убийца в петле времени (Kill Me Again, 2023). На удивление хорошо. Тот редкий случай, когда не ждешь вообще ничего хорошего, а получаешь нормально сделанное кино с вменяемой развязкой. Ну и, прямо скажем, неожиданная вариация на тему "дня сурка".

Бастион 36 (Bastion 36, 2025). Неплохая криминальная драма. Но мне не хватало динамики, какие-то эпизоды просто проматывал, т.к. ну очень уж скучно было.

Казнить нельзя помиловать (Mercy, 2026). Первые 2/3 было прям хорошо. Затем началось что-то невнятное в виде погони и вокруг нее, что очень сильно испортило впечатление. В конце есть хороший твист, который, к сожалению, испорченное впечатление исправить уже не смог.

Сериалы

Мошенники (второй сезон, 2026). Отличное продолжение отличного сериала.

Ночной администратор (The Night Manager, второй сезон, 2025). Если понравился первый сезон, то можно посмотреть и второй. Местами второй похуже (мне выбор некоторых актеров показался странным), местами получше. Буду ждать продолжения.

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

Вторая семья (первый сезон, 2023). Купился на очень высокий рейтинг на Кинопоиске. Как по мне, средней паршивости. Основной сюжет вроде норм, но некоторые детали оставляют вопросы "ну как так-то?"

Его и её (His & Hers, первый сезон 2026). Смотрибельно, хотя идиотизм некоторых персонажей меня откровенно раздражал. Финал неожиданный, но, как по мне, выглядит несколько чужеродно и притянуто за уши.

Художник (второй сезон, 2025). Начало еще более-менее смотрибельно, но вот завершение -- это просто какой-то позор.