Студопедия

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

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

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






Улучшения контейнеров






Что же случилось со стандартными контейнерами, после появления новых языковых возможностей и десяти лет дополнительного опыта? Прежде всего, у нас появилось несколько новых контейнеров: array (контейнер фиксированного размера), forward_list (односвязный список) и неупорядоченные контейнеры (хеш-таблицы). Потом, контейнеры начали использовать новые языковые возможности, такие как списки инициализаторов, rvalue ссылки, шаблоны с переменным числом аргументов и constexpr. Давайте в качестве примера рассмотрим std:: vector.

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

vector< string> vs = { " Hello", ", ", " World! ", " \n" };

for (auto s: vs) cout < < s;

  • Операторы перемещения. Контейнеры теперь содержат конструктор и оператор перемещения (в дополнение к существующим операциям копирования). Наиболее важным следствием из этого, является возможность эффективного возвращения из функций контейнеров:

vector< int> make_random(int n)

{

vector< int> ref(n);

// некоторый генератор случайных чисел

for(auto& x: ref) x = rand_int(0, 255);

Return ref;

}

vector< int> v = make_random(10000);

for (auto x: make_random(1000000)) cout < < x < < '\n';

Смысл здесь заключается в том, что вектор не копируется. Перепишите этот код с выделением вектора в куче и вы столкнетесь с проблемами управления памятью. Перепишите этот код так, чтобы вектор передавался в качестве аргумента в функцию make_random и вы получите значительно менее понятный код (в котором, к тому же, легче допустить ошибку).

  • Улучшенные операции добавления элементов. Моей любимой операцией контейнера является push_back(), которая позволяет элегантно увеличивать размер контейнеру:

vector< pair< string, int> > vp;

String s;

Int i;

while(cin> > s> > i) vp.push_back({s, i});

 

В этом коде будет создан объект pair< string, int>, по значениям s и i, который затем будет перемещен в vp. Обратите внимание, он будет не «скопирован», а «перемещен». Существует перегруженная версия метода push_back, которая принимает в качестве аргумента rvalue ссылку, что позволяет использовать конструктор перемещения класса string. Также обратите внимание на использование унифицированного синтаксиса инициализации, что приводит к более короткому коду.

  • Устанавливающие (emplace) операции. Метод push_back() использует конструктор перемещения, который значительно более эффективен по сравнению со стандартными операциями копирования, но мы можем пойти еще дальше. Зачем вообще что-то копировать/перемещать? Почему бы не выделить в векторе нужный объем памяти и просто не создать нужное значение прямо в этой памяти? Такие операции называются “emplace” (т.е. «создающие на месте»). Давайте в качестве примера рассмотрим emplace_back():

vector< pair< string, int> > vp;






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