std::future::get()


Желая побольнее уколоть мерзкого горбатого карлана Боба Гука, Айзек Ньютон писал, цитируя Иоанна Солсберийского, который вольно пересказал мысль Бернара Шартрского: «Если я видел дальше других, то потому, что стоял на плечах гигантов». Казалось бы, скромно сказано, но скрытый смысл этой едкой фразы иной. Ньютон намекал, что пока он совершал блестящие открытия, опираясь на научную базу предшественников, Боб совершал удачные подглядывания, опираясь афедроном о знаменитый стодвадцатитрехметровый шпиль Солсберецкого собора. Гук панч выкупил, и подействовала эпистола не хуже "новичка". Скаредный коротыш после такого выпада сыграл в ящик. Через тридцать лет почти, но это уже мелочи. Ньютона же сразу через два года после успешной ликвидации пошлая девица Анна одарила рыцарским званием. Все сходится.
Может быть, сэр Айзек и был не совсем прав, когда потом лично обмазал фекалиями единственный портрет Боба Гука, из-за чего человечество сегодня вообще не знает, как выглядел этот великий негодяй. Однако в одном он не ошибся: std::future будет работать, поскольку стоит на спинах горбатых карланов.
Вернее, на примитивах синхронизации, которые мы уже реализовали: мьютексы, условные переменные, once.
Перед сборкой нам осталось только проследить, как future возвращает полученное значение после томительного ожидания.
Реализация функции маскируется под нечто простое:
_𝚁𝚎𝚜 𝚐𝚎𝚝() {
𝚝𝚢𝚙𝚎𝚗𝚊𝚖𝚎 _𝙱𝚊𝚜𝚎_𝚝𝚢𝚙𝚎::_𝚁𝚎𝚜𝚎𝚝 __𝚛𝚎𝚜𝚎𝚝(*𝚝𝚑𝚒𝚜);
𝚛𝚎𝚝𝚞𝚛𝚗 𝚜𝚝𝚍::𝚖𝚘𝚟𝚎(𝚝𝚑𝚒𝚜->_𝙼_𝚐𝚎𝚝_𝚛𝚎𝚜𝚞𝚕𝚝()._𝙼_𝚟𝚊𝚕𝚞𝚎());
}
Более-менее понятно, что мы через move на всякий случай передаем владение результатом тому, кто вызовет get.
Сам объект результата берется из функции:
__𝚛𝚎𝚜𝚞𝚕𝚝_𝚝𝚢𝚙𝚎 _𝙼_𝚐𝚎𝚝_𝚛𝚎𝚜𝚞𝚕𝚝() 𝚌𝚘𝚗𝚜𝚝 {
_𝚂𝚝𝚊𝚝𝚎_𝚋𝚊𝚜𝚎::_𝚂_𝚌𝚑𝚎𝚌𝚔(_𝙼_𝚜𝚝𝚊𝚝𝚎);
_𝚁𝚎𝚜𝚞𝚕𝚝_𝚋𝚊𝚜𝚎& __𝚛𝚎𝚜 = _𝙼_𝚜𝚝𝚊𝚝𝚎->𝚠𝚊𝚒𝚝();
𝚒𝚏 (!(__𝚛𝚎𝚜._𝙼_𝚎𝚛𝚛𝚘𝚛 == 𝚗𝚞𝚕𝚕𝚙𝚝𝚛)) 𝚛𝚎𝚝𝚑𝚛𝚘𝚠_𝚎𝚡𝚌𝚎𝚙𝚝𝚒𝚘𝚗(__𝚛𝚎𝚜._𝙼_𝚎𝚛𝚛𝚘𝚛);
𝚛𝚎𝚝𝚞𝚛𝚗 𝚜𝚝𝚊𝚝𝚒𝚌_𝚌𝚊𝚜𝚝<__𝚛𝚎𝚜𝚞𝚕𝚝_𝚝𝚢𝚙𝚎>(__𝚛𝚎𝚜);
}
Здесь проверяем _M_state (тип __state_type), который таит в себе истинный статус контейнера - пионер он или не готов еще.
Затем сюрприз! Опять вызывается _M_state->wait(), так же как и в методе std::future::wait. Получается, что в явном виде его можно было и не вызывать. Кто же знал, провайдер в приступе усердия заблокировал мне cppreference.
Если вместо значения future принесет нам исключение, то мы немедленно перебросим его дальше.
Метод возвращает объект типа _Result, внутри которого действительно есть метод _M_value:
_𝚁𝚎𝚜 &_𝙼_𝚟𝚊𝚕𝚞𝚎() 𝚗𝚘𝚎𝚡𝚌𝚎𝚙𝚝 { 𝚛𝚎𝚝𝚞𝚛𝚗 *_𝙼_𝚜𝚝𝚘𝚛𝚊𝚐𝚎._𝙼_𝚙𝚝𝚛(); }
Просто извлекаем результат из хранилища.
Осталось только закрыть вопрос про typename _Base_type::_Reset, по всем признакам это RAII. По всем, кроме верности:
𝚜𝚝𝚛𝚞𝚌𝚝 _𝚁𝚎𝚜𝚎𝚝 {
𝚎𝚡𝚙𝚕𝚒𝚌𝚒𝚝 _𝚁𝚎𝚜𝚎𝚝(__𝚋𝚊𝚜𝚒𝚌_𝚏𝚞𝚝𝚞𝚛𝚎& __𝚏𝚞𝚝) 𝚗𝚘𝚎𝚡𝚌𝚎𝚙𝚝 : _𝙼_𝚏𝚞𝚝(__𝚏𝚞𝚝) { }
~_𝚁𝚎𝚜𝚎𝚝() { _𝙼_𝚏𝚞𝚝._𝙼_𝚜𝚝𝚊𝚝𝚎.𝚛𝚎𝚜𝚎𝚝(); }
__𝚋𝚊𝚜𝚒𝚌_𝚏𝚞𝚝𝚞𝚛𝚎& _𝙼_𝚏𝚞𝚝;
};
_Reset запоминает переданную ему ссылку на базовый класс future, и при выходе из области видимости уничтожается, попутно вызывая метод reset у _M_state.
Логично, ведь мы передаем владение результирующим объектом через метод get, и после вызова оного нужно уничтожить все. Вспомогательные объекты, контейнеры, все-все спалить. Дотла.
Нужен только результат.
Довольно слов, я медленно достаю пылящуюся на полке отладочную плату...
Просмотры: 29
Открыть в MAX Сообщить о неточности

Репосты публикации

Публикация канала

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

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

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

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

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

Перейти