TGViewer
this->notes. this->notes. @thisnotes · 4.51K subscribers
Post #513 631
#cpp

Представьте вот такой код:

auto object = GetObject(params...);

auto another = object;
MessAround(object);

// (1) you want to write some logic here

Где MessAround — функция, которая непредсказуемым образом меняет значение вашего object. То есть значение соответствует всем инвариантам, но вы не знаете, какое конкретно.

Как вы будете писать код в (1)?

Вы наверное проверите какие-то свойства вашего object. Может он там empty()/isNull()/valid(). Или может вы сразу решите его почистить: clear(). Или может присвоить что-нибудь туда захотите: object = Object{1, 2, 3}.
Или можете вообще сравнить его с чем-то (вдруг там всё-таки какое-то конкретное значение появилось):

if (object == "str_val"_obj) {...}


Делаете ли вы что-то неправильное? Должен ли компилятор вам подсказать проблему в таком коде? Может UBsan? Может clang-tidy?

Да нет.

Более того, даже если вы сделаете что-то такое:

auto first = object["first"];

Вы возможно ничего плохого не сделали. Вы просто не знаете, что точно там лежит. MessAround туда могло подложить что угодно.

Конечно, проблемы могут возникнуть, если вы, не проверив состояние вашего объекта, будете предполагать, что он обладает какими-то свойствами. Например, думать, что он не пустой. Или что он содержит сколько-то каких-то элементов. Это всё может быть, но вообще-то мы точно утверждать не можем.

Использовать объект после MessAround это примерно то же самое, что написать функцию, решающую некоторую задачу в вакууме. На примере функции, решающей любую задачу:

void solve(Object obj) {...}

Вы опять же про этот obj ничего не знаете. Вам надо проверить разные корнер кейсы. А потом как-то там решать вашу проблему.

Чем эти примеры отличаются от работы с переменной после std::move?

Да ничем.

Мы так яро привыкли к правилу «использовать переменную после std::move опасно», что в нашей ментальной модели это часто равносильно undefined behaviour. Уже само это действие вызывает подозрения. Code smell так называемый.

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

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

Отсюда рождаются ментальные модели вида
• «после std::move ничего нельзя»
• «после std::move можно только переприсваивать или уничтожать объект, всё остальное запрещено».
Это упрощения, которые мы себе придумали, чтобы меньше думать. И они почти всегда работают. Но иногда всё же нет.

Давайте думать и не вестись на вот эти попытки наших развитых эволюционировавших мозгов упрощать. Это мы профессионально ленимся.

P.S. Важно подчеркнуть ещё один факт.
Состояние объекта после std::move — всем известное «valid but unspecified». По стандарту это работает для стандартной библиотеки. Но кажется, мы уже настолько к этому привыкли, что считаем это данностью в любом случае. Не то чтобы это ожидание обосновано. Авторы библиотек делают что хотят. Но наверное писать ломающий это ожидание код всё-таки не надо.
А для стандартной библиотеки довольно просто понять, можно ли вызывать метод у мувнутого объекта: у метода не должно быть precondition. Например у std::vector::front он есть: !empty(); у std::vector::clear такого нет.

@thisnotes. Patreon, newsletter.
Спасибо Artyom Garkavy и niki4smirn.
  • 👍 12
  • 👎 2
More from @thisnotes
  1. Sep 17, 2026#common Сидите вы себе спокойно, разрабатываете поиск каких-нибудь объектов. Может это тов…
  2. Sep 9, 2026#cpp #books Да, книга 2001ого года. Мы ровесники. И да, в ней в основном обсуждаются какие…
  3. Sep 2, 2026#perf Попробовал собрать в кучку (кажется, немного сумбурно всё же) мысли по двум моментам…
  4. Aug 31, 2026Давайте новый тег заведём: #perf Во-первых, надо понять, что я вообще понимаю под перфом,…
  5. Aug 27, 2026#common Мы часто делаем системы, которые обладают какими-то ограничениями. Ограничения наш…
  6. Aug 24, 2026#list 0. [talk] Achieving Peak Performance for Matrix Multiplication in C++. Aliaksei Sala…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →