Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






String s;






Int i;

while(cin> > s> > i) vp.emplace_back(s, i);

 

  • Устанавливающие (emplace) методы принимают шаблонный параметр с переменным числом аргументов (variadic template), который используется для создания требуемого типа. Является ли метод emplace_back() действительно более эффективным по сравнению с методом push_back() зависит от используемого типа и реализации (библиотеки и шаблонов с переменным числом аргументов). Если вы считаете, что эта разница может быть существенной, то измерьте ее. В противном случае отталкивайтесь от эстетических соображений и выбирайте между vp.push_back({s, i}) и vp.emplace_back(s, i); по вашему вкусу. Сейчас я предпочитаю использовать push_back(), но я могу изменить свою точку зрения в будущем.
  • Аллокаторы области видимости (scoped allocators). Контейнеры теперь могут хранить «настоящие объекты-аллокаторы (с состоянием)», и использовать их для управления вложенными выделениями памяти (например, для выделения памяти под элементы контейнера).

Очевидно, что контейнеры – это не единственное место стандартной библиотеки, которое пользуется преимуществами новых языковых возможностей. Так, например:

  • Вычисления времени компиляции (compile-time evaluation): constexpr используется для гарантированного вычисления выражений во время компиляции для bitset, duration, char_traits, complex, array, для атомарных типов, случайных чисел и т.д.
  • Кортежи (tuples): Кортежи были бы невозможны без шаблонов с переменным числом аргументов.

 

Аллокаторы с дополнительным состоянием

Для простоты и компактности контейнеров С++98 не требует от них поддержки аллокаторов с состоянием. Аллокаторы не должны были хранится в объектах контейнеров. Такое поведение все еще используется по умолчанию в С++11, но появилась возможность использования аллокаторов с состоянием, например, можно использовать аллокатор, содержащий указатель на область памяти из которой происходит выделение. Например:

// Вариант для C++98не содержит данных

template< class T> class Simple_alloc {

// обычная реализация аллокатора

};

class Arena {

void* p;

Int s;

public:

Arena(void* pp, int ss);

// выделяет из диапазона p[0..ss-1]

};

template< class T> struct My_alloc {

Arena& a;

My_alloc(Arena& aa): a(aa) { }

// обычная реализация аллокатора

};

Arena my_arena1(new char[100000], 100000);

Arena my_arena2(new char[1000000], 1000000);

// память выделяется аллокатором по умолчанию

vector< int> v0;

// выделяет из my_arena1

vector< int, My_alloc< int> > v1(My_alloc< int> {my_arena1});

// выделяет из my_arena2

vector< int, My_alloc< int> > v2(My_alloc< int> {my_arena2});

// выделяет с помощью Simple_alloc

vector< int, Simple_alloc< int> > v3;

 

Обычно, для облегчения синтаксиса используют typedef.

Нет никакой гарантии того, что Simple_alloc и аллокатор, используемый по умолчанию столкнутся с нехваткой памяти, но это можно гарантировать с помощью небольшого количества метапрограммирования шаблонов. Таким образом, использование аллокатора приводит к дополнительному расходу памяти только в том случае, когда аллокатор обладает состоянием (как My_alloc).

При использовании пользовательских аллокаторов с контейнерами может возникнуть одна коварная проблема: должен ли элемент располагаться в той же самой выделенной области, что и контейнер? Например, если вы используете Your_allocator для Your_string для выделения его элементов, и я использую My_allocator для выделения элементов в объекте My_vector, тогда какой аллокатор должен использоваться для элементов в типе My_vector< Your_allocator> >? Решение заключается в возможности указать контейнеру какой аллокатор должен передаваться его элементам. Например, предположим, что у меня есть аллокатор My_alloc и я хочу, чтобы vector< string> использовал My_alloc дляэлементов вектора и для выделения элементов строки. Прежде всего, нужно создать версию строки с My_alloc.



// строка с нужным аллокатором

using xstring = basic_string< char,

char_traits< char>, My_alloc< char> >;

 

Затем, мне нужно создать версию vector, принимающую строки и My_alloc, и передающий этот аллокатор строке:

using svec = vector< xstring,

scoped_allocator_adaptor< My_alloc< xstring> > >;

 

Теперь мы можем создать аллокатор типа My_alloc< xstring>:

svec v(svec:: allocator_type(My_alloc< xstring> {my_arena1}));

 

Теперь svec – это вектор строк, который использует My_alloc для выделения памяти для своих элементов. Новое поведение заключается в использовании «адаптера» (“wrapper”) из стандартной библиотеки под названием scoped_allocator_adaptor, который указывает на то, что строки также должны использовать My_alloc. Обратите внимание, что адаптер может (очень легко) преобразовывать My_alloc< xstring>, требуемый типу xstring.

Так что у нас есть 4 варианта:

// vector и string используют свой собственный

// аллокатор (аллокатор по умолчанию):

using svec0 = vector< string>;






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.