back to the std::future
Привели мы как-то нашего ПМ-а в цирк. Никогда до этого не был. А там по арене наматывают круги кони, бегемот сквозь горящие кольца прыгает, на простынях под куполом гимнасты корчатся. Вот дрессированные коты ходят строем, олень на табуретке кеглями жонглирует, бегают клоуны и обливают друг друга желтой водицей. Три часа как на одном дыхании.
За время представления ПМ ни разу не улыбнулся, постоянно отвлекался, записывал что-то в телефоне.
Мы его спрашиваем:
- Не понравилось, да?
- Почему? - строго взглянул на нас. - Понравилось, спасибо.
И опять что-то в сотике набирает.
На следующий день назначает митинг про новую стратегию управления.
- Вчера, наконец-то, я понял, как должны выглядеть процессы в нашей компании, - говорит с чикатильской улыбкой, - нам нужна Continuous Incremental Resilient Collaborative User-centric Sustainable Strategy!
И открывает презентацию:
"
CIRCUS Strategy — это подход к управлению разработкой, основанный на непрерывной и инкрементальной поставке ценности через устойчивую к изменениям и высококоллаборативную среду, с фокусом на потребности пользователя и сохранением стабильного темпа команды".
Три часа как на одном дыхании. В конце всем сказал поставить себе цели на год. Не к добру это.
Пока поставил себе целью разобраться окончательно в кружевах и подпорочках
std::future. В прошлый раз успели только убедиться, что результат
std::promise на самом деле принадлежит разделяемому состоянию. Это значит, что в отличие от депутатов,
promise раздает не только обещания, но и возвращает вожделенное значение.
В роли обещания выступает объект
std::future, и получить его проще, чем отказ на собеседовании.
Достаточно вызвать простой надежный советский метод
get_future(), чтоб получить немного надежды на будущий результат.
future<_Res> get_future(){ return future<_Res>(_M_future); }
Для друзей у
std::future есть особый конструктор:
explicit future(const __state_type& __state) : _Base_type(__state) { }
Где тип аргумента
__state_type это тип разделяемого состояния и есть.
typedef shared_ptr<_State_base> __state_type;
Можно ошибочно предположить, что фьючерсы можно раздавать всем подряд,
shared_ptr все стерпит. Однако взгляните на функцию извлечения:
_Res get() { typename _Base_type::_Reset __reset(*this); return std::move(this->_M_get_result()._M_value());}Метод
этот в Химках уже видели. Кажется, мы вернулись к тому, с чего начинали. Как вы хорошо помните,
_Res - это тип шаблонного аргумента
std::future. Возвращаем мы не просто копию объекта типа
_Res, а через
move отдаем владение результатом страждущему. Более того, разделяемое состояние сбрасывается через RAII
__reset.
Все эти факты мягко намекают нам, что метод
get одноразовый!
При повторном вызове функция проверки в методе
_M_get_result бросит исключение
std::future_error с кодом
no_state.
template<typename _Tp>static void _S_check(const shared_ptr<_Tp>& __p) { if (!static_cast<bool>(__p)) __throw_future_error((int)future_errc::no_state);}Но ско
рее всего, так далеко мы зайти не успеем. Будем остановлены на стадии получения второго
std::future.
Особый конструктор для друга у
std::future есть, но он с подвохом.
Конструктор
future вызывает конструктор базового класса
__basic_future
explicit __basic_future(const __state_type& __state) { _State_base::_S_check(_M_state); _M_state->_M_set_retrieved_flag();}Провер
ка
_S_check ничего вам не сделает, а вот
_M_set_retrieved_flag...
Сей атомный флаг как раз отслеживает, передавалось ли уже это разделяемое состояние в какой-нибудь
std::future. Такой интересный костыль для
shared_ptr:
void _M_set_retrieved_flag() { if (_M_retrieved.test_and_set()) __throw_future_error(int(future_errc::future_already_retrieved));}Если
уже передавался, то бросаем исключение с кодом
future_already_retrieved.
А, ну и цели почти во всех компаниях - это
карго-культ.