dangling reference
Освежающая легкость летнего утра давно сменилась вязкими предрассветными холодами. Потом, если едкая прохлада и отступала, то день все равно оставался придавлен низкими серыми облаками. Тяжесть эта отдавалась в теле, распадаясь внутри на тоску и туман. Такой же поднимался вечерами в поле от безымянной речки. Плотный и сырой, огромными ватными клочьями выползал на берег.
От этой картины сами собой закрывались глаза, голова чугунела и тянула вниз.
"Возраст наверное, - подумал я, и, лихо по-стариковски крякнув, оторвался от стула, - четверть века прожить - чай, не поле перейти..."
Тут же закружилась голова.
"И вот третьего дня в спину вступило, вчера в ухе стреляло, - мысленно стал перебирать неизлечимые болезни, зевнул, - э-эх, и указатели ломит, деструктор отваливается... а ссылки-то! Ссылки прям висят..."
Да, такое бывает. Многие мужчины старше сорока лет сталкиваются с такой проблемой. Не конец света.
По-научному она называется "проблема синхронизации времени жизни объектов". Чаще всего проявляется у тех, кто любит баловаться потоками.
Тут легче всего поймать рассинхрон, особенно когда есть какие-нибудь thread_local переменные.


void thread_worker(int id) { Signal s{1}; thread_local Signal tls{2};}Класс

Signal тут просто для иллюстрации


struct Signal { int x; Signal(int x) : x{x} { std::cout << "+sig" << x << "\r\n"; } ~Signal() { std::cout << "-sig" << x << "\r\n"; }};Просто п

осмотрим, кто, где и когда:

+sig1+sig2Эт

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

-sig1-sig2То

есть, тут концепция RAII подводит нас под монастырь. Вы ожидаете... ну хорошо, я ожидаю, что деструктор s будет вызван после уничтожения tls, а выходит наоборот.
Казалось бы, ерунда. Однако, если постараться, то можно поймать серьезные проблемы.
Например, при использовании эксклюзивных ресурсов и отсоединенных потоков, вы же любите так делать?


std::mutex mtx;bool is_done = false;struct ExclusiveResource {...} gasoline;
void thread_worker() { thread_local Vehicle track{gasoline}; ... std::lock_guard<std::mutex> lock{mtx}; is_done = true;
}Обычный рабочий п

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

int main() { std::thread t(thread_worker); t.detach();
while(true) { std::lock_guard<std::mutex> lock{mtx}; if (is_done) break; } gasoline.spoil(); // Но поток еще работает! return 0
;}Теперь выпускаем пот

ок на свободу через detach и ждем его завершения. Выглядит глупо, конечно, но это для примера, я так не пишу на самом деле. Обычно не пишу. А если и пишу, то не я.
Так вот, lock в thread_worker разрушается ближе к концу, но поток, как и Ленин, все еще живой.
Зато в главном потоке мы выходим из цикла и портим из вредности наш эксклюзивный ресурс - gasoline.spoil().
Допустим, объект тотально разрушен, но в рабочем потоке наступает очередь деструктора track, который попытается выполнить gasoline.unload() на римских развалинах. Дальше, сами понимаете, случается катастрофа.
Просмотры: 27
Открыть в MAX Сообщить о неточности

Сообщить о неточности

Опишите, что нужно исправить. Если есть источник, добавьте ссылку.

Вы покидаете datool.ru

Ссылка ведёт на внешний сайт. datool.ru не отвечает за его содержимое — проверьте адрес, прежде чем вводить пароли или платёжные данные.

Переход через 10 с

Перейти