Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Design Overview

Boost , The Boost C++ Libraries BoostBook Documentation Subset , Chapter 42. Boost.Variant

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Design Overview

"Never-Empty" Guarantee

The Guarantee

Все экземпляры v типа вариант гарантируют, что v сконструировал содержимое одного из типов Ti, даже если операция на v ранее не удалась.

Это означает, что вариант можно рассматривать именно как союз точно его ограниченных типов. Это свойство «никогда не пустое» изолирует пользователя от возможности неопределенного вариантного контента и значительной дополнительной сложности использования, связанной с такой возможностью.

The Implementation Problem

Хотя изначально «очевидной» может показаться «никогда не пустая» гарантия , на самом деле даже не совсем понятно, как ее реализовать в целом (т.е. без необоснованных ограничительных дополнительных требований к ограниченным типам ).

Центральная трудность возникает в деталях задания вариант . Приведены два примера v1 и v2 некоторого конкретного варианта Тип, есть два различных, фундаментальных случая, которые мы должны рассмотреть для назначения v1 = v2.

Для начала рассмотрим случай, когда v1 и v2 содержат значения одного и того же типа. Назовите этот тип T. В этой ситуации назначение совершенно простое: используйте T::operator=.

Однако мы также должны рассмотреть случай, когда v1 и v2 содержат значения различных типов. Звони. Эти типы T и U. В этот момент, поскольку вариант управляет своим содержимым в стеке, левая сторона задания (т.е. v1) должна уничтожить его содержимое, чтобы разрешить копирование на месте содержимого правой стороны (т.е. v2). В конце концов, в то время как v1 начинается с содержимого типа T, оно заканчивается содержанием типа U, а именно копией содержимого v2.

Суть проблемы заключается в следующем: если копирование содержимого v2 терпит неудачу, как может v1 сохранить свою гарантию «никогда не пустой»? К тому времени, когда была предпринята попытка копирования из v2, v1 уже уничтожил его содержание!

The "Ideal" Solution: False Hopes

Узнав об этой дилемме, умные люди могут предложить следующую схему, надеясь решить проблему:

  1. Обеспечить некоторое «резервное» хранение, соответствующим образом выровненное, способное удерживать значения содержащегося типа левой стороны.
  2. Копировать память (например, используя memcpy) из хранилища левой стороны в резервное хранилище.
  3. Попробуйте скопировать содержимое правой стороны в (теперь воспроизведенное) хранилище левой стороны.
  4. В случае исключения из копии, восстановите резервную копию (т.е. скопируйте память из резервного хранилища обратно в левое боковое хранилище).
  5. В противном случае, в случае успеха, теперь скопируйте память левого бокового хранилища в другое «временное» выровненное хранилище.
  6. Теперь восстановите резервную копию (т.е. повторное копирование памяти) в хранилище левой стороны; с восстановленным «старым» содержимым, вызовите разрушитель содержащегося типа на хранилище левой стороны.
  7. Наконец, скопируйте память временного хранилища в (теперь пустое) хранилище левой стороны.

Несмотря на сложность, такая схема может обеспечить желаемую безопасность относительно эффективным способом. Фактически, несколько ранних итераций библиотеки реализовали именно этот подход.

К сожалению, как отметил Дэйв Абрахам, схема приводит к неопределенному поведению:

Это много кода для чтения, но если он делает то, что я думаю, он делает, это неопределенное поведение.

"Это трюк, чтобы переместить биты для существующего объекта в буфер, чтобы мы могли предварительно построить новый объект в этой памяти, а затем переместить старые биты назад временно, чтобы уничтожить старый объект?

"Стандарт не дает лицензии на это: только один объект может иметь заданный адрес за один раз. См. 3.8, и в частности пункт 4"

Кроме того, как быстро показывает тщательное изучение, эта схема может создать непримиримые расовые условия в одновременных условиях.

В конечном счете, даже если вышеописанная схема может быть выполнена для работы на определенных платформах с конкретными компиляторами, все равно необходимо найти переносное решение.

An Initial Solution: Double Storage

Узнав о невозможности вышеуказанной схемы, Энтони Уильямс предложил в [Wil02] схему, служившую основой для переносного решения в некоторых предрелизных реализациях варианта.

Основная идея этой схемы, которая должна называться схемой «двойного хранения», состоит в том, чтобы обеспечить достаточное пространство в пределах варианта для удержания двух отдельных значений любого из ограниченных типов.

При вторичном хранении копия правой стороны может быть предпринята без предварительного уничтожения содержимого левой стороны; соответственно, содержимое левой стороны остается доступным в случае исключения.

Таким образом, с помощью этой схемы реализация варианта должна только отслеживать, какое хранилище содержит контент, и отправлять любые запросы на посещение, запросы и т. Д. Соответственно.

Наиболее очевидным недостатком этого подхода является накладные расходы. Хотя некоторые оптимизации могут быть применены в особых случаях, чтобы устранить необходимость двойного хранения - для определенных ограниченных типов или в некоторых случаях полностью (см. раздел под названием & #8220; Включение оптимизации & #8221; для более подробной информации) - многие пользователи в списке рассылки Boost решительно возражали против использования двойного хранения. В частности, было отмечено, что накладные расходы по двойному хранению будут действовать в любое время, даже если назначение на вариант никогда не произойдет. По этой и другим причинам был разработан новый подход.

Current Approach: Temporary Heap Backup

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

С этой целью Дэйв Абрахамс предложил включить в спецификацию поведения для вариантного назначения следующее: «вариантное назначение от одного типа к другому может повлечь за собой динамическое распределение». То есть, в то время как вариант будет продолжать хранить свое содержимое in situ после строительства и после назначения с участием идентичных содержащихся типов, вариант будет хранить свое содержимое на куче после назначения с участием различных содержащихся типов.

Алгоритм назначения будет действовать следующим образом:

  1. Копирование-конструирование содержимого правой стороны к куче; вызов указателя на эти данные p.
  2. Уничтожить содержимое левой стороны.
  3. Копировать p в хранилище с левой стороны.

Поскольку все операции с указателями не являются роу, эта схема позволила бы варианту выполнить свою никогда не пустую гарантию.

Самая очевидная проблема этого подхода заключается в том, что, хотя он, безусловно, устраняет накладные расходы на двойное хранение, он вводит накладные расходы на динамическое распределение для назначения вариантного - не только с точки зрения первоначального распределения, но и в результате непрерывного хранения контента на куче. В то время как первая проблема неизбежна, последняя проблема может быть предотвращена с помощью следующего метода «временного резервного копирования»:

  1. Копи-конструкция содержимого слева-рука к куче; вызов указателя на эти данные backup.
  2. Уничтожить содержимое левой стороны.
  3. Копирование - конструирование содержимого правой стороны в (теперь пустом) хранилище левой стороны.
  4. В случае сбоя скопируйте backup в левый боковой накопитель.
  5. В случае успеха раскройте данные, указанные в backup.

С помощью этой техники: 1) используется только одно хранилище; 2) распределение находится на куче в долгосрочной перспективе только в случае неудачи назначения; и 3) после любого успешного назначения гарантировано хранение в пределах варианта . Для целей первоначального выпуска библиотеки эти характеристики были сочтены удовлетворительным компромиссным решением.

Однако остаются заметные недостатки. В частности, могут быть некоторые пользователи, для которых распределение кучи должно быть предотвращено любой ценой; для других пользователей может потребоваться любое распределение через поставляемый пользователем распределитель. Эти вопросы будут рассмотрены в будущем (см. раздел под названием “ Будущее направление: реализация на основе политики”). На данный момент библиотека рассматривает хранение своего контента как деталь реализации. Тем не менее, как описано в следующем разделе, есть определенные вещи, которые пользователь может сделать, чтобы обеспечить максимальную эффективность для вариантных экземпляров (см. раздел под названием “ Включение оптимизации ” для деталей).

Enabling Optimizations

Как описано в разделе под названием “ The Implementation Problem”, главной сложностью в реализации никогда не пустой гарантии является возможность неудавшейся копи-конструкции при задании вариант . Тем не менее, типы с конструкторами копий без бровей явно никогда не сталкиваются с этой возможностью. Аналогичным образом, если один из ограниченных типов варианта не может быть построен по умолчанию, то такой тип может быть использован в качестве безопасного типа «обратной копии» в случае неисправной конструкции копии.

Соответственно, вариант предназначен для обеспечения следующих оптимизаций при соблюдении следующих критериев по его ограниченным типам:

  • Для каждого ограниченного типа T, который не может быть сконструирован с помощью браузера (как указано в boost::has_nothrow_copy), библиотека гарантирует, что variant будет использовать только одно хранилище и конструкцию на месте для T.
  • Если любой ограниченный тип невозможен по умолчанию (как указано boost::has_nothrow_constructor), библиотека гарантирует, что вариант будет использовать только одно хранилище и конструкцию на месте для каждый ограниченный тип в варианте . Заметим, однако, что в случае невыполнения задания неопределенный неконструируемый по умолчанию ограниченный тип будет построен по умолчанию в левом боковом операнде, чтобы сохранить никогда не пустую гарантию.

Примечание к реализации : Чтобы сделать поведение вариантного более предсказуемым после исключения, текущая реализация предпочитает конструировать по умолчанию boost::blank, если он указан как ограниченный тип вместо других неконструируемых по умолчанию ограниченных типов. (Если эта функция считается полезной, она станет частью спецификации для варианта ; в противном случае она может быть устаревшей.) Пожалуйста, предоставьте обратную связь со списком рассылки Boost

Future Direction: Policy-based Implementation

Как показали предыдущие разделы, было потрачено много усилий, чтобы обеспечить баланс между производительностью, размером данных и использованием кучи. Кроме того, значительные оптимизации могут быть включены в вариант на основе определенных признаков его ограниченных типов.

Тем не менее, будут некоторые пользователи, для которых выбранный компромисс является неудовлетворительным (например: распределение кучи должно быть предотвращено любой ценой; если распределение кучи используется, должны использоваться пользовательские распределители и т. Д.). По этой причине будущая версия библиотеки будет поддерживать реализацию на основе политики вариант . Хотя это не устранит проблем, описанных в предыдущих разделах, это позволит пользователям, а не разработчикам библиотек, принимать решения о компромиссах.


PrevUpHomeNext

Статья Design Overview раздела The Boost C++ Libraries BoostBook Documentation Subset Chapter 42. Boost.Variant может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: Chapter 42. Boost.Variant ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 17:50:31/0.029838085174561/1