Продолжая наш пример онлайн-игры, предположим, что у нас есть огромный класс для обработки текстур рендеринга:
classtexture{public:texture(conststd::string&filename){/*loadstexturefile*/}conststd::string&get_filename()const;// rest of the interface};
И мы решили использовать<flyweight<texture>>, чтобы облегчить манипулирование этими объектами. Теперь рассмотрим это, казалось бы, невинное выражение:
flyweight<texture>fw("grass.texture");
Обратите внимание, что для того, чтобы построить<fw>, мы неявно строим полный объект текстуры травы. Выражение в основном эквивалентно
flyweight<texture>fw(texture("grass.texture"));
Это неприемлемо дорого: мы строим массивный временный объект только для того, чтобы в большинстве случаев его выбросить. Вполне вероятно, что у Flyweight уже есть внутренний эквивалентный объект, с которым будет связан<fw>— распределение стоимости является ключевой особенностью модели Flyweight. В этом конкретном примере имена файлов текстуры выступают в качествеключак реальным объектам текстуры: два объекта текстуры, построенные из одного и того же имени файла, эквивалентны. Таким образом, мы хотели бы, чтобы имена файлов использовались для поиска текстуры и каким-то образом убедиться, что дорогостоящая конструкция текстуры выполняется только тогда, когда не было найдено эквивалентное значение.
<flyweight<T>>делает это различие между ключом и значением размытым, поскольку он использует<T>как тип ключа, так и связанный с ним тип значения. Когда это неэффективно, как в нашем примере текстуры, мы можем явно указать оба типа, используя конструкцию<key_value>:
Так называемыеключевые весыимеют форму<flyweight<key_value<K,T> >>: Ключевой тип<K>используется для внутреннего поиска соответствующих значений типа<T>. Основные весы гарантируют, что<T>значения не построены, за исключением случаев, когда не существует другого эквивалентного значения; такое строительство осуществляется из связанного<K>значения.
Помимо семантики на основе ключа на время строительства, весы с ключевым значением ведут себя так же, как и обычные весы, хотя некоторые различия сохраняются. Рассмотрим следующий код, который не представляет проблем с обычными весами:
Задание не может работать, потому что ключ типа<std::string>необходим для внутреннего поиска, в то время как мы передаем объект с полной текстурой. Действительно, код производит ошибку компиляции, аналогичную этой:
error: 'boost::mpl::assertion_failed' : cannot convert parameter 1 from
'boost::mpl::failed ************(__thiscall boost::flyweights::detail::
regular_key_value<Key,Value>::rep_type::no_key_from_value_failure::
NO_KEY_FROM_VALUE_CONVERSION_PROVIDED::* ***********)(std::string,texture)'
to 'boost::mpl::assert<false>::type'...
Получается, что мы можем выполнить задание, если только предоставим средство для извлечения ключа из стоимости. Это не всегда возможно, но в нашем конкретном примере класс текстуры сохраняет имя файла, используемое для построения, как указано функцией<texture::get_filename>. Мы используем это преимущество, указав подходящийключевой экстракторв рамках определения типа мухоловки:
structtexture_filename_extractor{conststd::string&operator()(consttexture&x)const{returnx.get_filename();}};flyweight<key_value<std::string,texture,texture_filename_extractor>>fw;...fw=get_texture(obj);// OK now
Спецификация ключевого экстрактора в определении веса-ключа приводит к оптимизации внутреннего пространства, поскольку ключи не должны храниться вдоль значений, а извлекаются из них. Таким образом, всегда полезно предоставить ключевой экстрактор, когда это возможно, даже если ваша программа не содержит заявлений о назначении.
Примеры2и5в разделе примеров используют весы с ключевым значением.
Многие из требований, предъявляемых к<T>дляобычных весов, переходят на ключевой тип в случае ключевого значения<flyweight<key_value<K,T> >>. Теперь<K>должно быть<Assignable>,<Equality
Comparable>и взаимодействовать сBoost.Hash, где равенство и хеш-совместимость являются требованиями, налагаемыми внутренней фабрикой Boost по умолчанию. Вес может изменяться, если этот завод дополнительно настроен или заменен пользователем. Единственное требование, которое сохраняется на<T>, заключается в том, что он должен быть сконструирован из<K>; только в том случае, если весу лета непосредственно назначен<T>объект, также<T>требуется быть<Assignable>. Для сериализации объектов типа<flyweight<key_value<K,T> >>нужно только<K>.
Статья Boost.Flyweight Documentation - Tutorial - Key-value flyweights раздела Boost.Flyweight Documentation - Tutorial может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.