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

How to use Boost.Intrusive

Boost , The Boost C++ Libraries BoostBook Documentation Subset , Chapter 17. Boost.Intrusive

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

Если вы планируете вставить класс в назойливый контейнер, вы должны принять некоторые решения, влияющие на определение класса. Каждый класс, который будет использоваться в инвазивном контейнере, нуждается в некоторых соответствующих элементах данных, хранящих информацию, необходимую для контейнера. Мы возьмем простой назойливый контейнер, назойливый список<boost::intrusive::list>, для следующих примеров, но все.Контейнеры очень похожи. Чтобы составить пример с использованием<boost::intrusive::list>, просто включите:

#include <boost/intrusive/list.hpp>

Каждый класс, который должен быть вставлен в назойливый контейнер, должен содержать крючок, который будет предлагать необходимые данные и ресурсы для вставки в контейнер. СBoost.Вы просто выбираете крючок, чтобы быть общедоступным базовым классом или публичным членом класса, который будет вставлен.Навязчивыйтакже предлагает более гибкие крючки для продвинутых пользователей, как объясняется в главеИспользование функциональных крючков, но обычно базовые или членские крючки достаточно хороши для большинства пользователей.

<list>Вы можете получить из<list_base_hook>.

template <class ...Options>
class list_base_hook;

Класс может принять несколько вариантов.Навязчивыеклассы получают аргументы в виде<option_name<option_value>>. Вы можете указать следующие варианты:

  • <tag<classTag>>: Этот аргумент служит меткой, поэтому вы можете вывести из более чем одного<list_base_hook>и, следовательно, поместить объект в несколько навязчивых списков одновременно. Неполный тип может служить тегом. Если вы указали два базовых крюка, выдолжныуказать разные метки для каждого из них. Пример:<list_base_hook<tag<tag1>>>. Если тег не указан по умолчанию, он будет использоваться (подробнее о тегах по умолчанию позже).
  • <link_mode<link_mode_type LinkMode>>: Второй аргумент шаблона контролирует политику связывания.Boost.Intrusiveв настоящее время поддерживает 3 режима:<normal_link>,<safe_link>и<auto_unlink>. По умолчанию используется<safe_link>режим. Подробнее об этом в разделахБезопасные крючкииАвтоматические крючки. Пример:<list_base_hook<link_mode<auto_unlink>>>
  • <void_pointer<classVoidPointer>>: этот вариант - тип указателя, который используется внутри крючка. Значение по умолчанию<void*>, что означает, что в крючке будут использоваться необработанные указатели. Подробнее об этом в разделе под названиемИспользование умных указателей с помощью Boost. Навязчивые контейнеры. Пример:<list_base_hook< void_pointer< my_smart_ptr<void>>>

Для следующих примеров давайте забудем опции и используем значения по умолчанию:

#include <boost/intrusive/list.hpp>
using namespace boost::intrusive;
class Foo
   //Base hook with default tag, raw pointers and safe_link mode
   :  public list_base_hook<>
{ /**/ };

После этого мы можем определить навязчивый список:

template <class T, class ...Options>
class list;

<list>получает тип, который должен быть вставлен в контейнер<T>, в качестве первого параметра и необязательно пользователь может указать параметры. У нас есть 3 типа вариантов:

  • <base_hook<classHook>>/<member_hook<classT,classHook,HookT::*PtrToMember>><value_traits<classValueTraits>>: Все эти параметры определяют связь между типом<T>, который будет вставлен в список, и крюком (поскольку мы можем иметь несколько крючков в одном<T>типе).<member_hook>будет объяснено немного позже, и<value_traits>будет объяснено вконтейнерах с пользовательскими товарными знаками.Если опция не указана, контейнер будет сконфигурирован для использования базового крючка с тегом по умолчанию. Некоторые опции, настроенные для крючка (тип указателей, режим ссылки и т.д.), будут распространяться на контейнер.
  • <constant_time_size<boolEnabled>>: Указывается, требуется ли для контейнера функция постоянного времени<size()>. Это позволит инвазивному контейнеру хранить дополнительный элемент, чтобы отслеживать текущий размер контейнера. По умолчанию активируется постоянный размер времени.
  • <size_type<classSizeType>>: Указывает неподписанный тип, который может содержать размер контейнера. Этот тип будет типом, возвращенным<list.size()>, и типом, хранящимся в интрузивном контейнере, если<constant_time_size<true>>запрашивается. Обычно пользователю не нужно менять этот тип, но некоторые контейнеры могут иметь<size_type>, которые могут отличаться от<std::size_t>(например, контейнеры, подобные STL, используют<size_type>, определенный их распределителем).Boost.Intrusiveможет использоваться для реализации таких контейнеров, определяющих тип размера. По умолчанию это<std::size_t>.

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

typedef list<Foo> FooList;

Пример навязчивого списка с непостоянным размером времени, который будет храниться Объекты Фу:

typedef list<Foo, constant_time_size<false> > FooList;

Помните, что пользователь должен указать базовый крючок в декларации контейнера, если базовый крючок не имеет метки по умолчанию, поскольку это обычно означает, что тип имеет более одного базового крючка, и контейнер должен знать, какой крючок будет использовать:

#include <boost/intrusive/list.hpp>
using namespace boost::intrusive;
struct my_tag1;
struct my_tag2;
typedef list_base_hook< tag<my_tag>  > BaseHook;
typedef list_base_hook< tag<my_tag2> > BaseHook2;
class Foo   :  public BaseHook, public BaseHook2
{ /**/ };
typedef list< Foo, base_hook<BaseHook>  > FooList;
typedef list< Foo, base_hook<BaseHook2> > FooList2;

Как только список определен, мы можем использовать его:

//An object to be inserted in the list
Foo foo_object;
FooList list;
list.push_back(object);
assert(&list.front() == &foo_object);

Иногда нежелательна связь «is-a» между крючками списка и типами значений списка. В этом случае использование членского крючка в качестве члена данных вместо «нарушения» иерархии может быть правильным способом: вы можете добавить общедоступный член данных<list_member_hook<...>>в свой класс. Этот класс может быть сконфигурирован с теми же опциями, что и<list_base_hook>, за исключением опции<tag>:

template <class ...Options>
class list_member_hook;

Пример:

#include <boost/intrusive/list.hpp>
class Foo
{
   public:
   list_member_hook<> hook_;
   //...
};

При использовании членских крючков опция<member_hook>используется для настройки списка:

//This option will configure "list" to use the member hook
typedef member_hook<Foo, list_member_hook<>, &Foo::hook_> MemberHookOption;
//This list will use the member hook
typedef list<Foo, MemberHookOption> FooList;

Теперь можно использовать контейнер:

//An object to be inserted in the list
Foo foo_object;
FooList list;
list.push_back(object);
assert(&list.front() == &foo_object);

Однако у членских крючков есть некоторые ограничения реализации: Если существует виртуальная наследственная связь между родителем и крюком-членом, то расстояние между родителем и крюком не является фиксированным значением времени компиляции, поэтому получение адреса родителя от крючка-члена невозможно без обратного инженерного компилятора, произведенного RTTI. Кроме того, нестандартный указатель на реализацию членов для классов со сложными наследственными отношениями в совместимых компиляторах MSVC ABI не поддерживается членскими крючками, поскольку он также зависит от информации RTTI, произведенной компилятором.

Вы можете вставить один и тот же объект в несколько интрузивных контейнеров одновременно, используя один крючок на контейнер. Это полный пример использования базовых и членских крючков:

#include <boost/intrusive/list.hpp>
#include <vector>
using namespace boost::intrusive;
class MyClass : public list_base_hook<>
{
   int int_;
   public:
   list_member_hook<> member_hook_;
   MyClass(int i) :  int_(i)  {}
};
//Define a list that will store MyClass using the base hook
typedef list<MyClass> BaseList;
//Define a list that will store MyClass using the member hook
typedef member_hook
   < MyClass, list_member_hook<>, &MyClass::member_hook_> MemberOption;
typedef list<MyClass, MemberOption> MemberList;
int main()
{
   typedef std::vector<MyClass>::iterator VectIt;
   //Create several MyClass objects, each one with a different value
   std::vector<MyClass> values;
   for(int i = 0; i < 100; ++i)  values.push_back(MyClass(i));
   BaseList baselist;
   MemberList memberlist;
   //Now insert them in the reverse order in the base hook list
   for(VectIt it(values.begin()), itend(values.end())
      ; it != itend  ; ++it){
      baselist.push_front(*it);
   }
   //Now insert them in the same order as in vector in the member hook list
   for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it)
      memberlist.push_back(*it);
   //Now test lists
   {
      BaseList::reverse_iterator rbit(baselist.rbegin());
      MemberList::iterator mit(memberlist.begin());
      VectIt  it(values.begin()), itend(values.end());
      //Test the objects inserted in the base hook list
      for(; it != itend; ++it, ++rbit)
         if(&*rbit != &*it)   return 1;
      //Test the objects inserted in the member hook list
      for(it = values.begin(); it != itend; ++it, ++mit)
         if(&*mit != &*it)    return 1;
   }
   return 0;
}

Даже если интерфейс<list>похож на<std::list>, его использование немного отличается: Вы всегда должны иметь в виду, что вы непосредственно храните объекты в навязчивых контейнерах, а не в копиях. Срок службы хранимого объекта не связан и не управляется контейнером:

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

PrevUpHomeNext

Статья How to use Boost.Intrusive раздела The Boost C++ Libraries BoostBook Documentation Subset Chapter 17. Boost.Intrusive может быть полезна для разработчиков на c++ и boost.




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



:: Главная :: Chapter 17. Boost.Intrusive ::


реклама


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

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