Boost.Containerстремится к полному соответствию C++11, за исключением обоснованных отклонений, максимально возможной обратной передачи для C++03. Очевидно, что это соответствие находится в процессе разработки, поэтому в этом разделе объясняется, какие функции C++11 реализованы и какие из них были репортированы в компиляторы C++03.
Для компиляторов с ссылками на значение rvalue и для типов C++03, использующихУсиление. Переместитьэмуляцию ссылки на значениеBoost.Containerподдерживает все функции C++11, связанные с семантикой перемещения: контейнеры подвижны, требования к<value_type>указаны для контейнеров C++11.
Для компиляторов с вариадными шаблонамиBoost.Containerподдерживает вставку размещения (<emplace>, ...) функций с C++11. Для этих компиляторов без поддержки вариадных шаблоновBoost.Containerиспользует препроцессор для создания набора перегрузок до конечного числа параметров.
C++03 не был дружественным к государственному распределению. Для компактности контейнерных объектов и простоты не требовалось, чтобы контейнеры поддерживали распределители с состоянием: Объекты распределения не должны храниться в контейнерах. Хранить распределитель с состоянием было невозможно, скажем, распределитель, который держит указатель на арену, из которой выделять. C++03 позволил реализаторам предположить, что два распределителя одного и того же типа всегда равны (это означает, что память, выделенная одним объектом распределения, может быть размещена другим экземпляром того же типа), и распределители не были заменены, когда контейнер был заменен.
C++11 дополнительно улучшает поддержку государственного распределителя через<std::allocator_traits>.<std::allocator_traits>- это протокол между контейнером и распределителем, и автор распределителя может настроить свое поведение (должен ли контейнер распространять его в конструкторе движения, свопе и т. Д.) В соответствии с требованиями<allocator_traits>.Boost.Containerне только поддерживает эту модель с помощью C++11, но ивозвращает ее на C++03через<boost::container::allocator_traits>, включая некоторые изменения C++17. Этот класс предлагает некоторые обходные пути для компиляторов C++03 для достижения тех же гарантий распределения, что и<std::allocator_traits>.
В контейнерах, если это возможно, один распределитель удерживается для построения<value_type>с. Если контейнеру нужен вспомогательный распределитель (например, распределитель массива, используемый<deque>или<stable_vector>), этот распределитель также хранится в контейнере и инициализируется из предоставленного пользователем распределителя, когда контейнер построен (т.е. он не построен на лету, когда требуется вспомогательная память).
C++11 улучшает государственные распределители с введением шаблона классов<std::scoped_allocator_adaptor>.<scoped_allocator_adaptor>инстанцируется одним внешним распределителем и нулем или более внутренних распределителей.
Ограниченный распределитель - это механизм автоматического распространения состояния распределителя на подобъекты контейнера контролируемым образом. Если внутренний распределитель имеет только один тип распределителя, он становится самим<scoped_allocator_adaptor>, используя, таким образом, один и тот же ресурс распределения для контейнера и каждого элемента в контейнере, и, если сами элементы являются контейнерами, каждый из их элементов рекурсивно. При наличии более чем одного распределителя первый распределитель является внешним распределителем для использования контейнером, второй распределитель передается конструкторам элементов контейнера, а если сами элементы являются контейнерами, третий распределитель передается элементам элементов и так далее.
Boost.Containerреализует свой собственный класс<scoped_allocator_adaptor>ивозвращает эту функцию также в компиляторы C++03. Из-за ограничений C++03 в этих компиляторах распространение распределителя, реализованное<scoped_allocator_adaptor::construct>функциями, будет основано на признаках<constructible_with_allocator_suffix>и<constructible_with_allocator_prefix>, предложенных вN2554: предложение модели выделенного распределителя (Rev 2). В соответствии с компиляторами C++11 или компиляторами, поддерживающими выражения SFINAE (когда<BOOST_NO_SFINAE_EXPR>НЕ определено), признаки игнорируются, а правила C++11 (<is_constructible<T,Args...,inner_allocator_type>::value>и<is_constructible<T,allocator_arg_t,inner_allocator_type,Args...>::value>) будут использоваться для определения того, должен ли распределитель распространяться с аргументами суффикса или префикса распределителя.
Boost.ContainerреализуетC++14 Null Forward Iterators, что означает, что итераторы с инициализацией значений могут сравниваться и сравниваться с другими итераторами с инициализацией значений того же типа. Итераторы с инициализацией значений ведут себя так, как если бы они ссылались на конец одной и той же пустой последовательности (пример взят из N3644):
vector<int>v={...};autoni=vector<int>::iterator();autond=vector<double>::iterator();ni==ni;// True.nd!=nd;// False.v.begin()==ni;// ??? (likely false in practice).v.end()==ni;// ??? (likely false in practice).ni==nd;// Won't compile.
<vector>не поддерживает строгие гарантии исключения, данные<std::vector>в таких функциях, как<insert>,<push_back>,<emplace>,<emplace_back>,<resize>,<reserve>или<shrink_to_fit>для копируемых или не перемещаемых классов. В C++11move_if_no exceptиспользуется для поддержания гарантий безопасности исключения C++03 в сочетании с семантикой перемещения C++11. Эта сильная гарантия исключения ухудшает производительность вставки копируемых и метательных типов, ухудшая переходы к копиям, когда такие типы вставляются в вектор с использованием вышеупомянутых элементов.
Эта сильная гарантия исключений также исключает возможность использования некоторого типа перераспределений на месте, которые могут дополнительно улучшить производительность вставки<vector>См.Расширенные распределители, чтобы узнать больше об этих оптимизациях.
<vector>всегда использует конструкторы/назначения перемещения для перегруппировки элементов в векторе и использует механизмы расширения памяти, если распределитель поддерживает их, предлагая при этом только основные гарантии безопасности. Он отменяет гарантии исключения для улучшения производительности.
//Given std::vector<int> vv.insert(v.begin(),v[2]);//v[2] can be changed by moving elements of vector//Given std::list<int> l:l.remove(*l.begin())//The operation could delete the first element, and then continue trying to access it.
Принятая резолюция NAD (Not A Defect) подразумевает, что предыдущие операции должны быть четко определены. Это требует, чтобы код обнаруживал ссылку на вставленный элемент и дополнительную копию в этом случае, влияя на производительность даже тогда, когда ссылки на уже вставленные объекты не используются. Обратите внимание, что эквивалентные функции, принимающие значения r или диапазоны итераторов, требуют элементов, которые еще не вставлены в контейнер.
Boost.Containerприоритизирует производительность и не реализовал разрешение NAD: в функциях, которые могут изменять аргумент, библиотека требует ссылок на элементы, не хранящиеся в контейнере. Использование ссылок на вставленные элементы приводит к неопределенному поведению (хотя в режиме отладки это нарушение предварительного условия может быть уведомлено через BOOST_ASSERT).
Специализация<vector<bool>>была довольно проблематичной, и было несколько неудачных попыток обесценить или удалить ее из стандарта.Boost.Containerне реализует его, поскольку существует превосходноерешение Boost.DynamicBitset. Для вопросов с<vector<bool>>см. следующие документы:
& #8220;Но жаль, что комитет по C++ дал этой превосходной структуре данных название вектори что он не дает никаких указаний или поощрений по критическим общим алгоритмам, которые необходимо оптимизировать для этой структуры данных. Следовательно, немногие реализации std::lib идут на эту проблему.& #8221;
& #8220;В 1998 году признание того, что комитет допустил ошибку, было спорным. С тех пор Java пришлось обесценивать такие значительные части своих библиотек, что идея C++ была бы высмеяна за обесценивание одной небольшой специализации шаблонов.& #8221;
& #8220;<vector<bool>>не является контейнером и<vector<bool>::iterator>не является итератором случайного доступа (или даже передним или двунаправленным итератором, если на то пошло). Это уже нарушило пользовательский код в поле таинственным образом.& #8221;
& #8220;<vector<bool>>вынуждает всех пользователей выбирать конкретную (и потенциально плохую) оптимизацию, закрепляя ее в стандарте. Оптимизация преждевременна, у разных пользователей разные требования. Это также уже навредило пользователям, которые были вынуждены внедрять обходные пути, чтобы отключить «оптимизацию» (например, используя вектори вручную отливая в / из була).& #8221;
Так<boost::container::vector<bool>::iterator>возвращает реальные<bool>ссылки и работает как полностью совместимый контейнер. Если вам нужна оптимизированная для памяти версия<boost::container::vector<bool>>, используйтеBoost.DynamicBitset.
Boost.Containerиспользует<std::memset>с нулевым значением для инициализации некоторых типов, поскольку в большинстве платформ эта инициализация дает желаемую инициализацию значения с улучшенной производительностью.
Следуя стандарту C11,Boost.Containerпредполагает, чтодля любого целого типа представление объекта, где все биты равны нулю, должно быть представлением значения ноль в этом типе. Поскольку<_Bool>/<wchar_t>/<char16_t>/<char32_t>также являются целыми типами в C, он рассматривает все интегральные типы C++ как инициализируемые через<std::memset>.
По умолчаниюBoost.Containerтакже считает типы с плавающей запятой инициализируемыми с использованием<std::memset>. Большинство платформ совместимы с этой инициализацией, но в случае, если эта инициализация нежелательна, пользователь может<#defineBOOST_CONTAINER_MEMZEROED_FLOATING_POINT_IS_NOT_ZERO>включить заголовки библиотеки.
По умолчанию он также считает, что типы указателей (указатель и указатель для типов функций, за исключением указателей объектов-членов и функций-членов) могут быть инициализированы с использованием<std::memset>. Большинство платформ совместимы с этой инициализацией, но в случае, если эта инициализация нежелательна, пользователь может<#defineBOOST_CONTAINER_MEMZEROED_POINTER_IS_NOT_ZERO>включить заголовки библиотеки.
Если ни<BOOST_CONTAINER_MEMZEROED_FLOATING_POINT_IS_NOT_ZERO>, ни<BOOST_CONTAINER_MEMZEROED_POINTER_IS_NOT_ZERO>не определеныBoost.Containerтакже считает, что типы POD могут быть инициализированы через<std::memset>со значением ноль.
Статья C++11/C++14 Conformance раздела The Boost C++ Libraries BoostBook Documentation Subset Chapter 9. Boost.Container может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.